N皇后问题
打表
#include<iostream> using namespace std; int a[11]={0,1,0,0,2,10,4,40,92,352,724}; int main() { int n; while(scanf("%d",&n)>0&&n) { printf("%d\n",a[n]); } return 0; }
/************************************************************ * Author : rudolf * Last modified : 2013-04-23 15:27 * Filename : caogao.cpp * Description : * *********************************************************/ #include <stdio.h> #include <iostream> #include<string.h> using namespace std; int map[20],a[20],hang[20],n,cnt; void DFS(int num) { int i,j,flag; if(num==n+1)//到n也成立了才会搜索n+1 { cnt++;return; } for(i=1;i<=n;i++) if(!hang[i])//不在同一行 { flag=1;map[num]=i;//第num列第i行放第num个皇后 for(j=1;j<num;j++) if((map[num]-num==map[j]-j)||(map[num]+num==map[j]+j))//判断是否在对角线上 { flag=0; break; } if(flag) { hang[i]=1; DFS(num+1);//递归调用 hang[i]=0;//回溯 } } } int main() { int i,m; for(i=1;i<11;i++)//打表列出N个皇后对应几种方法 { memset(map,0,sizeof(map)); memset(hang,0,sizeof(hang)); n=i;cnt=0; DFS(1); a[i]=cnt; } while(cin>>m&&m!=0) cout<<a[m]<<endl; return 0; }
/** n皇后问题,由于N 是小于等于10的正整数, 所以可以使用打表的方法把前十中情况全 部找出来存起来然后每次输入时不用重新 的计算了。 */ #include <stdio.h> #define NUMS 10 /*输入的数字1---10*/ int N; /*棋盘*/ int chessboard[11][11]; /* 用来记录拜访数目 */ int cal; /* 检查皇后放置此行此列是否可以,可以返回1,不可以返回0 此递归是一行一行找的,K是棋盘的长度 */ int dfs_check(int row,int column,int k) { /* 说明已经到了棋盘的界外,前边都符合了 */ if(row>k) { cal++; return 1; } /* 正上方是否有皇后*/ for(int i = 1; i < row; i++) /* 如果有皇后则返回不能放置这里返回0*/ if(chessboard[i][column] == 1) return 0; /* 左右上方45度角检查是否可以*/ /* 左上方*/ for(int i=row-1,j=column-1;i>0&&j>0;i--,j--) if(chessboard[i][j] == 1) return 0; /* 右上方*/ for(int i=row-1,j=column+1;i>0&&j<=k;i--,j++) if(chessboard[i][j] == 1) return 0; /*标记这个位置成功了*/ chessboard[row][column] = 1; /*进行下一行搜索*/ for(int i=1;i<=k;i++) if(dfs_check(row+1,i,k)==1) break; chessboard[row][column] = 0; return 0; } int main() { int i,j,k; int count[11]; /*打表*/ for(k=1;k<=NUMS;k++) { count[k] = 0; cal = 0; /*首先将棋盘初始化全部置为0*/ for(i=0;i<=NUMS;i++) for(j=0;j<=NUMS;j++) chessboard[i][j]=0; for(i=1;i<=k;i++) dfs_check(1,i,k); count[k] = cal; } while(scanf("%d",&N)!=EOF&&N!=0) printf("%d\n",count[N]); return 0; }
回溯法(转)能力有限,理解不了他的代码http://blog.csdn.net/alongela/article/details/6755770
用回溯法就可以解决,设皇后的编号依次为1,2,……,n,则可以认为第i个皇后必须摆放在第i行,然后枚举第一个皇后的位置进行回溯,若某一次发现某个皇后无法找到摆放位置则直接返回,如果所有皇后都可以找到摆放位置,则说明存在一种摆法满足要求,统计有多少种摆法即可。
此题n<=10,测试数据中会有大量重复数据,因此要保存答案,遇到曾经计算过的n直接输出即可,否则可能会超时。
#include<iostream> using namespace std; int n; int x[100]; int ans[11]; bool Place(int k) { int i = 1; while (i<k) { if (x[i]==x[k] || abs(x[i]-x[k])==abs(i-k)) return false; i++; } return true; } int main() { int k, cnt; memset(ans, 0, sizeof(ans)); while (scanf("%d", &n)!=EOF && n!=0) { if (ans[n]>0) { printf("%d\n", ans[n]); continue; } x[1] = 0; k = 1, cnt = 0; while (k>0) { x[k]++; while (x[k]<=n && !Place(k)) { x[k]++; } if (x[k]<=n) { if (k==n) { cnt++; } else { k++; x[k] = 0; } } else k--; } ans[n] = cnt; printf("%d\n", cnt); } return 0; }
dfs
#include<iostream> #include<math.h> using namespace std; int s[12][12],n,count; int panduan(int h,int l) { for(int i=0;i<n;i++) //判断列 { if(s[i][l]==0||i==h) continue; else return 0; } for(i=0;i<n;i++) //判断行 { if(s[h][i]==0||i==l) continue; else return 0; } for(i=0;i<n;i++) //判断成45度的线 { for(int j=0;j<n;j++) { if(s[i][j]==0||(i==h&&j==l)) continue; else { if(abs(h-i)==abs(l-j)) //只要y=kx+b中abs(k)==1,说明成了45度的线 return 0; } } } return 1; } void dfs(int num,int f) { int i,j; if(num==n*n) { if(f==0) count++; return; } if(num>n*n)return; i=num/n; j=num%n; if(s[i][j]==0&&panduan(i,j)) { s[i][j]=1; dfs(num+1,f-1); s[i][j]=0; } dfs(num+1,f); } int main() { while(scanf("%d",&n)>0&&n) { memset(s,0,sizeof(s)); count=0; dfs(0,n); //printf("\n\n"); printf("%d\n",count); } return 0; }