N 皇后问题 回溯/深搜
来源:互联网 发布:配送软件 编辑:程序博客网 时间:2024/06/04 18:47
深度优先搜索:例如走迷宫,你没有办法用分身术来站在每个走过的位置,不撞南山不回头,利用栈这种数据结构来实现(利用递归便于实现,但是效率较低),找到的第一个解不一定是最优解,只是先序遍历最早的可行解。
回溯法试探法:按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。在现实中,有很多问题往往需要我们把其所有可能穷举出来,然后从中找出满足某种要求的可能或最优的情况,从而得到整个问题的解。回溯算法就是解决这种问题的“通用算法”,有“万能算法”之称。
Problem Description
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。
Input
共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。
Output
共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。
Sample Input
1
8
5
0
Sample Output
1
92
10
思路:根据深搜的模板来嵌套即可,唯一需要注意的就是判断条件。以行为标准,则不用判断行,直接判断列与斜线即可。
代码即是把上述内容表述出来。
本题存在一个小坑,就是应该用数组存储N皇后的结果,然后打表输出。
#include<cstdio>#include<cstrin>using namespace std;int map[12][12];int cnt=0;int n;bool ok(int i,int y){ for(int j=0;j<=y;j++) {//j描述行,因为一行行标点,所以只要判断前y点就好 if(map[j][i]==1)//判断同一列是否满足条件 return false; if(y-j>=0&&i-j>=0)//防止越界 if(map[y-j][i-j]==1)//判断左上斜线 return false; if(y-j>=0&&i+j<=n)//防止越界 if(map[y-j][i+j]==1)//判断右上斜线 return false; } return true;}void dfs(int y){ if(y==n){//结束递归条件 cnt++; } for(int x=0;x<n;x++){//x为列数,一列列填点。 if(ok(x,y)){//如果该点满足条件,填充。 map[y][x]=1; dfs(y+1); map[y][x]=0;//恢复棋盘。 } }}int main(){ int ans[11]={0}; for(n=1;n<=10;n++) { cnt=0; dfs(0);//搜索从0行开始 ans[n]=cnt; } while(~scanf("%d",&n)&&n) printf("%d\n",ans[n]); return 0;}根据上述的思路,可以进行空间复杂的简化
即用一个x[]数组存储的列,而下标代表行,判断斜线上的即可用绝对值的差值即可,次算法优化了存储空间,但对时间复杂度无太大影响都为31MS
#include <cstdio>#include <cmath>#include <cstring>#define N 15using namespace std;int x[N],result[N]; //皇后放置的列数int n; //皇后个数int sum=0; //可行解个数int place(int k){int i;for(i=1;i<k;i++) if(abs(k-i)==abs(x[k]-x[i])||x[k]==x[i]) return 0; return 1;}int queen(int k){int i;if(k>n)sum++;else for(i=1;i<=n;i++) { x[k]=i; if(place(k)) queen(k+1); } return sum;}int main(){for(n=1;n<=10;n++) { result[n]=queen(1); sum=0; }while(scanf("%d",&n)==1&&n!=0) printf("%d\n",result[n]);return 0;}
判断斜线上是否存在皇后,还有一种数学技巧,左上右下或左下右上斜线上共有2*n-1种情况
#include <iostream>#include <cstring>using namespace std;int n;int ans=0;bool a[20]; //列使用情况 true 用bool x1[20]; //左上*右下的情况bool y1[20]; //左下+右上的情况void dfs(int deep){ if(deep>=n){ ans++; return ; } for(int i=0;i<n;i++){ if(x1[i+deep]==false&&y1[i-deep+n]==false&&a[i]==false) { x[deep+i]=true; y1[i-deep+n]=true; a[i]=true; dfs(deep+1); x[deep+i]=false; y1[i-deep+n]=false; a[i]=false; } } }
- N 皇后问题 回溯/深搜
- 回溯:N皇后问题
- N皇后问题(回溯问题)
- 回溯算法n皇后问题
- n皇后问题回溯学习
- 回溯经典-n皇后问题
- n皇后问题-回溯法
- hdu2553-N皇后问题.回溯
- N皇后问题(回溯)
- N皇后问题(回溯)
- 【回溯法】n皇后问题
- N皇后问题,回溯法
- 简单回溯N皇后问题
- n皇后问题--递归回溯
- 经典回溯问题----n皇后
- 回溯法---n皇后问题
- N皇后问题 【回溯法】
- 【回溯法】n皇后问题
- 基于jq中奖记录效果实现
- 个人笔记(第七篇)
- 差分约束/并查集——BZOJ1202/Luogu2294 [HNOI2005]狡猾的商人
- Java实现全排列
- 基于CMMI软件工程的问题解答
- N 皇后问题 回溯/深搜
- windows10 python2.7 opencv3
- css 动画效果
- Redis命令总结
- python基础学习之——使用list和tuple
- 工程中编写自己的Makefile---1 一些基本概念
- 分布式相关文章收集(转)
- Java EE之Servlet、JSP学习
- css3提示文字弹窗代码