Solve the8-Queenproblem using back-trackingalgorithm.
解题思路:
这道题目可以使用回溯算法。这种方法的思想是:为了求得问题的解,先选择某一种可能情况向前探索,如果发现是错误的,则退回一步重新选择,继续向前探索,如此反复进行,直至得到解或者证明无解。要解决N皇后问题,其实就是要解决好怎么放置这n个皇后,每一个皇后与前面的所有皇后不能在同一行、同一列、同一对角线,在这里我们可以以行优先,就是说皇后的行号按顺序递增,只考虑第i个皇后放置在第i行的哪一列,所以在放置第i个皇后的时候,可以从第1列判断起,如果可以放置在第1个位置,则跳到下一行放置下一个皇后。如果不能,则跳到下一列...直到最后一列,如果最后一列也不能放置,则说明此时放置方法出错,则回到上一个皇后向之前放置的下一列重新放置。此即是回溯法的精髓所在。当第n个皇后放置成功后,即得到一个可行解,此时再回到上一个皇后重新放置寻找下一个可行解...如此后,即可找出一个n皇后问题的所有可行解。
复杂度分析:
复杂度小于n^3。棋盘是n行n列的,但是在每列选择可否放置的比较上又做了一次循环。但不是循环到n,而是根据皇后i的取值而变化的。所以复杂度应该是1/3n^3左右。
这是迭代的方法:
#include <cstdlib>
#include <iostream>
#include <math.h>
#define N 8
int x[N+1];//放置的列数
//int final[N+1][N+1];
using namespace std;
void print(int x[])
{
int i= 1;
for(int u = 1; u <= N; u++)
{
for(int v = 1; v <= N; v++)
{
if(u == i&& v == x[i])
cout << "*"<< " ";
else
cout << 0<< " ";
}
i++;
cout << endl;
}
cout<< endl;
//memset(final, 0,sizeof(final));//这个绝对不能加,每次memset要浪费很多时间
}
bool Place(int k)
{
int i= 1;
while(i < k)
{
if(x[i] == x[k] || abs(x[i] - x[k]) == abs(i -k))
//如果实在同一对角线上,则他们横坐标的差值和纵坐标的差值绝对值相同。
returnfalse;
else i = i + 1;
}
returntrue;
}
int NQuees(int num)
{
x[1] =0;
int k= 1;
while(k > 0)
{
x[k] = x[k] + 1;
while(x[k] <= N&& !Place(k))
{
x[k] =x[k] + 1;
//不断搜寻第k个皇后应该放的位置,直到找到合适的或者此行搜索完毕也没有发现合适的位置。
}
if(x[k] <= N)//搜索到合适的位置
{
if(k ==N)//如果对于第n个皇后已经搜索到,则可以打印x[k]
{
num++;
cout << "第"<< num<<"种:"<< endl;
print(x);
}
else//如果没有到达最后一行,则行数k加1。并且从第一列开始尝试。
{
k = k + 1;
x[k] = 0;
}
}
else k = k -1;//不能搜索到合适的位置则说明上面的步骤有问题,则回溯到上一行重新比对。
}
returnnum;
}
int main(int argc, char *argv[])
{
int num = 0;
cout<< "num:"<< NQuees(num)<< endl;
system("PAUSE");
returnEXIT_SUCCESS;
}
这是递归的方法:
#include <cstdlib>
#include <iostream>
#define N 8
using namespace std;
int final[N+1][N+1];
int x[N+1];
int sum = 0;
void print()
{
for(int u = 1; u <= N; u++)
{
for(int v = 1; v <= N; v++)
{
if(v == x[u])
cout << "*"<< " ";
else
cout << "0"<< " ";
}
cout << endl;
}
}
bool place(int k)
{
for(int i = 1; i< k; i++)
{
if(x[k] ==x[i] || abs(x[k] - x[i]) == abs(k - i))
return false;
}
return true;
}
int quees(int k)
{
if(k> N)
{
sum++;
cout<< "第"<< sum<< "种:"<<endl;
print();
cout<< endl;
}
else
{
for(int i = 1; i<= N; i++)
{
x[k] =i;
if(place(k))
{
quees(k+1);
}
}
}
returnsum;
}
int main(int argc, char *argv[])
{
quees(1);
cout<< sum<< endl;
system("PAUSE");
returnEXIT_SUCCESS;
}
迭代回溯和递归回溯差不多。递归回溯存在一个潜在的问题,即当n增大时,递归的复杂度也将是几何级的增长,可能出现重复的情况。回溯法的解就是展开一个树。比如说这个N皇后问题,好像当n>60的时候,回溯法就不能完全地解决问题了,这时可以考虑用概率算法来解决,它可以解决很大的基数,只不过结果不是很精确而已。