/**/ /**/ /**/ /************************************************************************/ /**/ /**/ /**/ /* 目前最快的N皇后递归解决方法 */ /**/ /**/ /**/ /************************************************************************/ #include < iostream > using namespace std;#include < time.h > long sum = 0 ,upperlim = 1 ; // 该算法的思想是遍历每一行(虽然算法中没有直接体现行遍历),然后对每一行中的所有 // 有效列(即与上面行已放置皇后在列和左右对角线方向上不会造成冲突的列)进行尝试 // row是代表已经遍历的列,1表示该列已被皇后占有了 void GetSum( long row, long rightdiagonal, long leftdiagonal)... ... { //每一列都被皇后占领了,表示该方案可行 if (row != upperlim) ......{ //下面进行行遍历 //row表示当前行中每一列放置了皇后,则该列在之后的行遍历中均不能再放置皇后了 //rightdiagonal表示在下一行的尝试中当前放置点的左一列位置(下一行左一列的点与当前放置 //点刚好形成了右对角线,会造成冲突)不可用 //同样的leftdiagonal表示在下一行的尝试中当前放置点的右一列(下一行右一列的点与当前放置 //点刚好形成了左对角线,会造成冲突)不可用 long pos = upperlim & ~(row | leftdiagonal | rightdiagonal); //这里得到该行中所有可以尝试的列(格),然后从右到左进行尝试 //如果遍历到的该行上的每一列已经都是无效的话则无需进行下一行的尝试了 while (pos) ......{ //该位操作能得到一个二进制数组中最右面的1的位置,如pos = 00010110进行如下操作之后 //p = 00000010,p的作用是取得当前遍历的行中所有有效列的最右面的一列(格)(其实每次取 //最左的列也行的) long p = pos & -pos; pos -= p; //p代表的是当前行上放置的列,递归调用函数遍历下一行 //此时需将本行的尝试的列在row中标记上表明下一行不可再在此列放置皇后了 //同时,在下一行中本放置点的左一列和右一列也需标记为不可再放置 GetSum(row+p, (rightdiagonal+p)<<1, (leftdiagonal+p)>>1); } } else ......{ sum++; }} int main( int argc, char * argv[])... ... { time_t tm; int n=15; if(argc!=1) n=atoi(argv[1]); tm=time(0); if((n<1)||(n>32)) ......{ printf(" heh..I can't calculate that. "); exit(-1); } printf("%d Queens ",n); //upperlim中前n位为1,用于标识探索是否已完成 upperlim=(upperlim<<n) - 1; GetSum(0,0,0); printf("Number of solutions is %ld, %d seconds ", sum,(int)(time(0)-tm)); return 0;} 下面一段转的是人家用string类写的一个实现.效率较低,但是比较好懂#include < iostream > #include < string > using namespace std; // t表示被占领的行,s表示未测试过的行 void queen( const string t, const string s) ... { if (s=="") printf("%s ",t.c_str()); else //第一个for循环测试当前测试列的每一行 for (int i=0; i<s.length(); i++) ...{ bool safe=true; //第二个for循环测试当前点与之前点是否处于同一对角线上 //由于字符串的设计巧妙,使判断冲突情况限制在了对角线的情况上而已 for (int j=0;j<t.length();j++) ...{ //列间隔等于行间隔 if (t.length()-j==abs(s[i]-t[j])) ...{ safe=false; break; } } if (safe) queen(t+s[i], s.substr(0,i)+s.substr(i+1)); }} int main() ... { //string中的每一位代表一列,从左到右开始,而每一位中的数字代表了每一行 //由于每个位的数字都是唯一的,因此可以保证已测试列和待测试列之间不会有 //行相同的情况 string s="01234567"; queen("",s); exit(EXIT_SUCCESS); return 0;}