33 N皇后问题
Posted 唐的糖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了33 N皇后问题相关的知识,希望对你有一定的参考价值。
原题网址:https://www.lintcode.com/zh-cn/old/problem/n-queens/#
n皇后问题是将n个皇后放置在n*n的棋盘上,皇后彼此之间不能相互攻击。
给定一个整数n,返回所有不同的n皇后问题的解决方案。
每个解决方案包含一个明确的n皇后放置布局,其中“Q”和“.”分别表示一个女王和一个空位置。
对于4皇后问题存在两种解决的方案:
[
[".Q..", // Solution 1
"...Q",
"Q...",
"..Q."],
["..Q.", // Solution 2
"Q...",
"...Q",
".Q.."]
]
你能否不使用递归完成?
1) 算法开始, 清空棋盘,当前行被设为第一行,当前列被设为第一列(即从0,0处开始扫描)
2) 在当前行,当前列的位置上判断是否满足条件(即保证经过这一点的行,列与斜线上都没有两个皇后),若不满足,跳到第4步
3) 在当前位置上满足条件的情形:
在当前位置放一个皇后,若当前行是最后一行,记录一个解;
若当前行不是最后一行,当前行设为下一行, 当前列设为当前行的第一个待测位置;
以下两步是当前行是最后一行情况下的执行步骤,即找其他解过程:
若当前行是最后一行,当前列不是最后一列,当前列设为下一列;
若当前行是最后一行,当前列是最后一列,回溯,即清空当前行及以下各行的棋盘,然后,当前行设为上一行,当前列设为当前行的下一个待测位置;
以上返回到第2步
4) 在当前位置上不满足条件的情形:
若当前列不是最后一列,当前列设为下一列,返回到第2步;
若当前列是最后一列了,回溯,有两种情况:若当前行已经是第一行了(说明找到所有解),算法退出,否则,清空当前行及以下各行的棋盘,然后,当前行设为上一行,当前列设为当前行的下一个待测位置,返回到第2步;
class Solution { public: /* * @param n: The number of queens * @return: All distinct solutions */ vector<vector<string>> solveNQueens(int n) { // write your code here vector<vector<string>> result; if (n<=0) { return result; } int * position=new int[n]; for (int i=0;i<n;i++) { position[i]=-1; } int row=0; placeQueen(result,row,position,n); delete []position; return result; } void placeQueen(vector<vector<string>> &result,int row,int * position,int n) { if (row==n) //最后一行处理完,寻找到一个解决方案,将其字符串数组化push到结果中; { string str(n,\'.\'); vector<string> temp(n,str); for (int i=0;i<n;i++) { temp[i][position[i]]=\'Q\'; } result.push_back(temp); } else { for (int j=0;j<n;j++)//寻找该行可以放置Q的列; { if (CanPlaceQ(row,j,position,n))//找到,则继续寻找下一行; { position[row]=j; placeQueen(result,row+1,position,n); } //找不到,j++,寻找该行的下一列; } } } bool CanPlaceQ(int row,int col,int * position,int n) { for (int i=0;i<row;i++) { if (position[i]==col||abs(row-i)==abs(col-position[i]))//判断是否在同一列或同一对角线; { return false; } } return true; } };
递归方法其他参考:https://blog.csdn.net/sinat_26230689/article/details/52206498 这个代码我看了几遍还是很懵……智商捉急,先把他的思路copy过来:
【解题思路】
深度遍历+回溯。
1. 从上到下,从左到右,判断某个位置是否可以放皇后,可以放,转2,不可以,转3;
2. 放置皇后,并判断是否已经放置N个皇后,如果是,记录结果并回溯(寻找其他解决方案);否则转1,递归判断下一行能否放置皇后;
3. 判断本行下一列是否可以放置皇后。如果本列无法放置皇后,剪枝;否则查看下一列能否放置皇后。
即,可以放置,就往下找;放不了,就往回看,拜托上层变一变,看能不能继续往下找,直到第一层都试过最后一列的位置,程序结束。
由于需要记录所有可行结果并输出,在每次得到可行结果时,将当前结果保存,并将Q还原为".",方便回溯。
class Solution { public: /* * @param n: The number of queens * @return: All distinct solutions */ bool CanPlaceQ(int row,int col,int * position,int n) { for (int i=0;i<row;i++) { if (position[i]==col||abs(row-i)==abs(col-position[i]))//判断是否在同一列或同一对角线; { return false; } } return true; } void placeQueen(vector<vector<string>> &result,int row,int * position,int n) { int i=0,j=0; while(i<n) { while(j<n) { if (CanPlaceQ(i,j,position,n)) { position[i]=j; j=0;//下一行判断时列从头开始; break; //直接判断下一行; } else { j++;//当前行当前列无法放Q,判断当前行下一列; } } if (position[i]==-1)//当前行没有可以放Q的位置,回溯; { if (i==0)//回溯到第一行也无解,说明找到所有解,退出程序; { break; } --i;//否则回溯到上一行; j=position[i]+1;//从上一行可以放Q的下一位开始判断; position[i]=-1;//注意清空上一行位置!!; continue; } if (i==n-1) //最后一行判断完且找到放Q位置,将当前解决方案放入结果中; { string str(n,\'.\'); vector<string> temp(n,str); for (int k=0;k<n;k++) { temp[k][position[k]]=\'Q\'; } result.push_back(temp); j=position[i]+1;//此时不能结束,要找下一个解决方案,继续判断当前行下一个位置是否符合要求; position[i]=-1;//注意当前位置的状态要置-1; continue; } i++; } } vector<vector<string>> solveNQueens(int n) { vector<vector<string>> result; if (n<=0) { return result; } int * position=new int[n]; for (int i=0;i<n;i++) { position[i]=-1; } int row=0; placeQueen(result,row,position,n); delete []position; return result; } };
以上是关于33 N皇后问题的主要内容,如果未能解决你的问题,请参考以下文章