【C++】n皇后问题
2016-12-03 20:42
148 查看
今天参加了郭崇山老师的练习赛,结果连第一道题都没做出来,尼玛十万级别的n皇后问题我说实在是不会啊……google了一下题解发现要用到遗传算法还有CSP最小冲突法什么的(http://blog.csdn.net/u013390476/article/details/50011261)心好累啊,把自己代码贴出来歇会先。
首先是用朴素的回溯法做的,毕竟好久没碰了,做出来先
后来想递归是不是太费时间了,然后用递推做了一下,发现其实差不多……
然后翻了一下白书,找到了以前八皇后问题的算法,把回溯法优化了一下(空间换时间而已)
然后又看到了http://blog.csdn.net/hackbuteer1/article/details/6657109 中提到的位运算,号称是csdn上最快的算法,可惜我还没怎么看明白(大致明白了意思,但是还是写不出来)
就这样吧,一道n皇后写了两小时。关键是这个十万级别的数量级实在是搞不定啊,还是自己太水了。
首先是用朴素的回溯法做的,毕竟好久没碰了,做出来先
//version 1回溯 #include <iostream> #include <algorithm> #define MAXN 100010 using namespace std; bool hassolve=false;//是否解出 int n; int line[MAXN]; void solve(int layer)//layer表示的是已经完成的最高层数 { if(hassolve==true) return; if(layer==n) { for(int i=1;i<=n;i++) { cout<<i<<" "<<line[i]<<endl; } hassolve=true; return; } int cur=layer+1;//当前所讨论的层数 //枚举 for(int i=1;i<=n;i++) { bool IsOk=true; for(int j=1;j<=layer;j++) { if(line[j]==i||i-cur==line[j]-j||i+cur==line[j]+j) { IsOk=false; break; } } if(IsOk==true) { line[cur]=i; solve(cur); } } //消除枚举的影响,以便进行下一次枚举 } int main(void) { cin>>n; for(int i=1;i<=n;i++) { if(hassolve==true) { break; } line[1]=i; solve(1); } return 0; }
后来想递归是不是太费时间了,然后用递推做了一下,发现其实差不多……
#include <iostream> #include <algorithm> #include <cstring> #define MAXN 100010 using namespace std; int main(void) { int n; int line[MAXN]; cin>>n; //递推 memset(line,0,sizeof(line)); int layer=0;//layer代表的是已经解出皇后的层数,如果说layer==i,那么line[i]应该已经知道 while(layer<n) { int cur=layer+1; //枚举第cur+1行的皇后位置 for(int i=line[cur]+1;i<=n;i++) { bool IsOk=true; //根据回溯法的算法来枚举皇后的位置 for(int j=1;j<=layer;j++) { //判断i是否可行 if(line[j]==i||i-cur==line[j]-j||i+cur==line[j]+j) { IsOk=false; break; } } //如果i可行, if(IsOk==true) { line[cur]=i; layer++; break; } } //如果当前情况无解,退回 if(cur==layer+1) { line[cur]=0; layer--; } } for(int i=1;i<=n;i++) { cout<<i<<" "<<line[i]<<endl; } return 0; }
然后翻了一下白书,找到了以前八皇后问题的算法,把回溯法优化了一下(空间换时间而已)
//version 1回溯 #include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #define MAXN 100010 using namespace std; bool hassolve=false;//是否解出 int n; int line[MAXN]; bool vis[3][MAXN]; void solve(int layer)//layer表示的是已经完成的最高层数 { if(hassolve==true) return; if(layer==n) { for(int i=1;i<=n;i++) { cout<<i<<" "<<line[i]<<endl; } hassolve=true; return; } int cur=layer+1;//当前所讨论的层数 //枚举 for(int i=1;i<=n;i++) { if(!vis[0][i]&&!vis[1][cur+i]&&!vis[2][cur-i+n]) { line[cur]=i; vis[0][i]=vis[1][cur+i]=vis[2][cur-i+n]=true; solve(cur); vis[0][i]=vis[1][cur+i]=vis[2][cur-i+n]=false; } } //消除枚举的影响,以便进行下一次枚举 } int main(void) { freopen("in.txt","r",stdin); cin>>n; memset(vis,false,sizeof(vis)); for(int i=1;i<=n;i++) { if(hassolve==true) { break; } line[1]=i; solve(1); } return 0; }
然后又看到了http://blog.csdn.net/hackbuteer1/article/details/6657109 中提到的位运算,号称是csdn上最快的算法,可惜我还没怎么看明白(大致明白了意思,但是还是写不出来)
/* ** 目前最快的N皇后递归解决方法 ** N Queens Problem ** 试探-回溯算法,递归实现 */ #include "iostream" using namespace std; #include "time.h" // sum用来记录皇后放置成功的不同布局数;upperlim用来标记所有列都已经放置好了皇后。 long sum = 0, upperlim = 1; // 试探算法从最右边的列开始。 void test(long row, long ld, long rd) { if (row != upperlim) { // row,ld,rd进行“或”运算,求得所有可以放置皇后的列,对应位为0, // 然后再取反后“与”上全1的数,来求得当前所有可以放置皇后的位置,对应列改为1 // 也就是求取当前哪些列可以放置皇后 long pos = upperlim & ~(row | ld | rd); while (pos) // 0 -- 皇后没有地方可放,回溯 { // 拷贝pos最右边为1的bit,其余bit置0 // 也就是取得可以放皇后的最右边的列 long p = pos & -pos; // 将pos最右边为1的bit清零 // 也就是为获取下一次的最右可用列使用做准备, // 程序将来会回溯到这个位置继续试探 pos -= p; // row + p,将当前列置1,表示记录这次皇后放置的列。 // (ld + p) << 1,标记当前皇后左边相邻的列不允许下一个皇后放置。 // (ld + p) >> 1,标记当前皇后右边相邻的列不允许下一个皇后放置。 // 此处的移位操作实际上是记录对角线上的限制,只是因为问题都化归 // 到一行网格上来解决,所以表示为列的限制就可以了。显然,随着移位 // 在每次选择列之前进行,原来N×N网格中某个已放置的皇后针对其对角线 // 上产生的限制都被记录下来了 test(row + p, (ld + p) << 1, (rd + p) >> 1); } } else { // row的所有位都为1,即找到了一个成功的布局,回溯 sum++; } } int main(int argc, char *argv[]) { time_t tm; int n = 16; if (argc != 1) n = atoi(argv[1]); tm = time(0); // 因为整型数的限制,最大只能32位, // 如果想处理N大于32的皇后问题,需要 // 用bitset数据结构进行存储 if ((n < 1) || (n > 32)) { printf(" 只能计算1-32之间\n"); exit(-1); } printf("%d 皇后\n", n); // N个皇后只需N位存储,N列中某列有皇后则对应bit置1。 upperlim = (upperlim << n) - 1; test(0, 0, 0); printf("共有%ld种排列, 计算时间%d秒 \n", sum, (int) (time(0) - tm)); system("pause"); return 0; }
就这样吧,一道n皇后写了两小时。关键是这个十万级别的数量级实在是搞不定啊,还是自己太水了。
相关文章推荐
- 【转】用c++实现的8皇后问题
- 8皇后问题Python与C++实现
- C/C++ N皇后问题
- C++ 输出全排列 简单递归 N皇后问题
- N皇后问题 c/c++
- 用c++实现的8皇后问题
- n皇后问题—回溯法 C++实现
- 经典算法---8皇后问题的C++实现
- C++回溯算法Demo:以4皇后问题为例
- n皇后问题(C++解决)
- C++ 解决8皇后问题
- 〖編程·C++〗回溯算法:排列树 - N皇后问题
- n皇后问题的非递归迭代算法(C++实现)
- n-皇后问题 C++实现 回溯法
- 八皇后问题c++ 代码
- N皇后问题的求解(C++代码)
- C++递归问题之二——n皇后问题:以四、八皇后为例,给定n个皇后要求将它们放在一个n维矩阵中,任意两个皇后不能出现在同一行、列、主副对角线上,输出具体的摆放方式
- N皇后问题 c++
- 华为OJ之N皇后问题(C++代码)
- C++基础算法学习——N皇后问题