N皇后问题
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5976 Accepted Submission(s): 2728
Problem Description
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。
你的任务是,对于给定的N,求出有多少种合法的放置方法。
Input
共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。
Output
共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。
Sample Input
1 8 5 0
Sample Output
1 92 10
Author
cgf
Source
Recommend
lcy
题目意思是:求出所有满足八皇后(属于排列求解)的解。用回溯法穷举出所有发生的可能,通过约束函数对其剪枝,求出可行解。
贴张4皇后解的图形分析
采用迭代和递归式两方式求出解(其约束函数相同):
迭代式(非递归)
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
#define N 11
int x[N];
int ans[N];
int s;
int place(int k)
{
int i;
for(i=1;i<k;i++)
{
if(x[i]==x[k] || abs(i-k)==abs(x[i]-x[k]))
return 0;
}
return 1;
}
void queen(int n)
{
for (int i=1; i<=n; i++) //初始化
x[i]=0;
int k=1;
while (k>=1)
{
x[k]=x[k]+1; //在下一列放置第k个皇后
while (x[k]<=n && !place(k))
x[k]=x[k]+1; //搜索下一列
if (x[k]<=n && k==n) { //得到一个解,输出
s++;
}
else if (x[k]<=n && k<n)
k=k+1; //放置下一个皇后
else {
x[k]=0; //重置x[k],回溯
k=k-1;
}
}
}
int main()
{
int n;
memset(ans,0,sizeof(ans));
while(scanf("%d",&n),n)
{
if(!ans[n])
{
s=0;
queen(n);
ans[n]=s;
}
cout<<ans[n]<<endl;
}
return 0;
}
递归式
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
#define N 11
int x[N];
int ans[N];
int s;
int place(int k)
{
int i;
for(i=1;i<k;i++)
{
if(x[i]==x[k] || abs(i-k)==abs(x[i]-x[k]))
return 0;
}
return 1;
}
void queen(int n,int t)
{
int i;
if (t>n)
{
s++;
return ;
}
for(i=1;i<=n;i++)
{
x[t]=i;
if(place(t))
queen(n,t+1);
}
}
int main()
{
int n;
memset(ans,0,sizeof(ans));
while(scanf("%d",&n),n)
{
if(!ans[n])
{
memset(x,0,sizeof(x));
s=0;
queen(n,1);
ans[n]=s;
}
cout<<ans[n]<<endl;
}
return 0;
}
通过对八皇后的理解。。更改代码即可求出N个数的全排列
#include <stdio.h>
#include <math.h>
#include <string.h>
#define N 11
int x[N];
int ans[N];
int s;
int place(int k)
{
int i;
for(i=1;i<k;i++)
{
if(x[i]==x[k])//这里与八皇后的约束条件少了一个,只要不在同一行,同一列即可
return 0;
}
return 1;
}
void queen(int n,int t)
{
int i;
if (t>n)
{
s++;//这里时候已经找到了一个可行解,输出数组X的元素即可,s所纪录的是所有的排列数
for(i=1;i<t;i++)
printf("%d ",x[i]);
printf("\n");
return ;
}
for(i=1;i<=n;i++)
{
x[t]=i;//因为每次选取的时候,数组X都把i的值放到其数组对应t下标中,虽然存取了所有可行与不可行的解,但是约束函数给予的只有可行解
if(place(t))
{
queen(n,t+1);
}
}
}
int main()
{
int n;
memset(ans,0,sizeof(ans));
while(scanf("%d",&n),n)
{
if(!ans[n])
{
memset(x,0,sizeof(x));
s=0;
queen(n,1);
printf("\n");
}
}
return 0;
}
求出了N的全排列 即可以求出N个数里面的M排列:
#include <stdio.h>
#include <math.h>
#include <string.h>
#define N 11
int x[N];
int ans[N];
int s;
int place(int k)
{
int i;
for(i=1;i<k;i++)
{
if(x[i]==x[k])//这里与八皇后的约束条件少了一个,只要不在同一行,同一列即可
return 0;
}
return 1;
}
void queen(int n,int t)
{
int i;
if (t>n)///////改变这里的结束范围即可,比如N个数里面求3个数的排列,只要把n改为3即可
{
s++;//这里时候已经找到了一个可行解,输出数组X的元素即可,X所纪录的是所有的排列数
for(i=1;i<t;i++)
printf("%d ",x[i]);
printf("\n");
return ;
}
for(i=1;i<=n;i++)
{
x[t]=i;//因为每次选取的时候,数组X都把i的值放到其数组对应t下标中,虽然存取了所有可行与不可行的解,但是约束函数给予的只有可行解
if(place(t))
{
queen(n,t+1);
}
}
}
int main()
{
int n;
memset(ans,0,sizeof(ans));
while(scanf("%d",&n),n)
{
if(!ans[n])
{
memset(x,0,sizeof(x));
s=0;
queen(n,1);
printf("\n");
}
}
return 0;
}