/*书中写的虽然代码短,但是不好理解是如何实现的,我根据自己的思路写的这个,思路很清晰
感觉没必要为了少几行代码将思路搞得很不一般,就像归并排序一样,末尾有元素剩余单独处理就好
循环不变性:初始进入循环的是有效元素,每次根据在栈中有没有找到相同元素判断是否可以入栈
入栈情况:
当栈满时,意味着找到了一种结果,记录并输出。然后y不变,x++,当然,如果x也到了最大值,就要回溯(此时的回溯必定可以找到有元素的x非最大值,因为此前的元素各不相同)
栈不满时,y++,x=0
不入栈的情况:
x没达到最大值,x++即可
x达到了最大值,回溯,回溯到的元素不是第一行最大值时,x++即可,否则,退出循环。这是循环退出的唯一条件
*/
#include<iostream>
#include"string.h"
using namespace std;
//试探回溯法解八皇后问题
struct Queen{
int x,y;
Queen(int xx=0,int yy=0):x(xx),y(yy){}
Queen(Queen& b){x=b.x;y=b.y;}
bool operator==(Queen b){
return x==b.x||y==b.y||x+y==b.x+b.y||x-y==b.x-b.y;
}
};
int find(Queen* solu,Queen& q,int lo,int hi){//查找范围[lo,hi),找不到返回hi
for(int i=lo;i<hi;i++){
if(solu[i]==q)return i;
}
return hi;
}
void placeQueens(int N){
Queen* solu=new Queen[N];int top=0;
//用数组模拟栈,入栈solu[top++]=q;出栈q=solu[--top];
int nsolu=0;//记录满足条件的答案的数量
Queen q(0,0);
solu[top++]=q;q.y++;
//不断的试探回溯,忒休斯的绳索是栈,入栈是进一步,出栈是退一步
while(1){
//循环不变性:初始进入循环的q是有效的
//首先判断q应该前进(入栈)还是后退(出栈)
int r=find(solu,q,0,top);
if(r==top){//前进
solu[top++]=q;
//判断是否满足题意,确保下一次循环内的元素满足条件
if(top==N){//得到满足题意的一个结果
nsolu++;
for(int i=0;i<N;i++)printf("%d ",solu[i].x);
printf("\n");
//得到下一个有效点,回溯,以进入下一次循环
while(q.x==N-1&&top>0)q=solu[--top];
q.x++;
}else{
q.y++;q.x=0;
}
}else{
if(q.x==N-1){//说明此种情况不符合条件,应回溯
while(q.x==N-1&&top>0)q=solu[--top];
if(top==0&&q.x==N-1)break;
else q.x++;
}else{
q.x++;
}
}
}
cout<<nsolu;
}
int main(){
//freopen("d:\\CodeBlockSpace\\input.txt","r",stdin);
placeQueens(8);
return 0;
}