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;
}