八皇后问题(DFS)

 例题1:百练 2754

描述

会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将8个皇后放在棋盘上(有8 * 8个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题。对于某个满足要求的8皇后的摆放方法,定义一个皇后串a与之对应,即a=b1b2...b8,其中bi为相应摆法中第i行皇后所处的列数。已经知道8皇后问题一共有92组解(即92个不同的皇后串)。给出一个数b,要求输出第b个串。串的比较是这样的:皇后串x置于皇后串y之前,当且仅当将x视为整数时比y小。
输入

第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数b(1 <= b <= 92)

输出
输出有n行,每行输出对应一个输入。输出应是一个正整数,是对应于b的皇后串。
样例输入
2
1
92
样例输出
15863724
84136275

分析:主要是满足条件分析:

其中A[cur]==A[j]是判断皇后是否会纵向攻击:
其中cur-A[cur]==j-A[j]||cur+A[cur]==j+A[j]语句的意思是:皇后(cur,A[cur])和皇后(j,A[j])是否在同一对角线上:
判断的原理如图所示:

0 1 2 3 4 5 6 7
-1 0 1 2 3 4 5 6
-2 -1 0 1 2 3 4 5
-3 -2 -1 0 1 2 3 4
-4 -3 -2 -1 0 1 2 3
-5 -4 -3 -2 -1 0 1 2
-6 -5 -4 -3 -2 -1 0 1
-7 -6 -5 -4 -3 -2 -1 0

(a) 格子(x,y)的y-x值标志了主对角线

0 1 2 3 4 5 6 7
1 2 3 4 5 6 7 8
2 3 4 5 6 7 8 9
3 4 5 6 7 8 9 10
4 5 6 7 8 9 10 11
5 6 7 8 9 10 11 12
6 7 8 9 10 11 12 13
7 8 9 10 11 12 13 14

 (b)格子(x,y)的y+x值标志了副对角线
用x表示行,y表示列,则有x1=cur,y1=A[cur]:X2=j;y2=A[j];
根据图中的数值关系,可知在同一主对角线满足:cur-A[cur]==j-A[j];在同一副对角线满足:cur+A[cur]==j+A[j]

#include<iostream>
using namespace std;
int A[10],num=1,B[100][10];
int DFS(int cur)
{   if(cur==8)
    {  for(int i=0;i<8;i++)  
         B[num][i]=A[i];
       num++;
    }
    else 
    for(int i=0;i<8;i++)
    {  int flag=1;
       A[cur]=i+1;
       for(int j=0;j<cur;j++)
         if(A[cur]==A[j]||cur-A[cur]==j-A[j]||cur+A[cur]==j+A[j]) {flag=0;break;} 
       if(flag) DFS(cur+1);
    }
}
int main()
{   int n,m;
    cin>>n;
    DFS(0);
    while(n--)
    {  cin>>m;
       for(int i=0;i<8;i++)
         cout<<B[m][i];
       cout<<endl;
    } 
    return 0;
}

题2:Tyvj 1080(N皇后),需要剪枝利用use[2][]直接判断当前的皇后所在列和两个对角线是否有其他的皇后,注意主对角线标志y-x可能为负,所以存储的时候要+n。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAX=15;
#define CLR(arr,val) memset(arr,val,sizeof(arr))
int n,sum,A[MAX],use[MAX][2*MAX];
void DFS(int cur)
{   if(cur==n)
    {   sum++;
        if(sum<=3)
        {   for(int i=0;i<n;i++)
                printf("%d ",A[i]);
            printf("\n");    
        }
    }
    else
    {   for(int i=0;i<n;i++)
            if(!use[0][i]&&!use[1][cur+i]&&!use[2][cur-i+n])//use[0][i]判读当前皇后所在列是否存在其它皇后
            {   A[cur]=i+1;
                use[0][i]=use[1][cur+i]=use[2][cur-i+n]=1; //used[1][cur+i]为副对角线
                DFS(cur+1);  
                use[0][i]=use[1][cur+i]=use[2][cur-i+n]=0; //use[2][cur-i+n]为主对角线 
            }
    }
}
int main()
{   while(scanf("%d",&n)!=EOF)
    {   sum=0;
        DFS(0);
        CLR(use,0);
        printf("%d\n",sum);
    }
    return 0;
}



 

你可能感兴趣的:(测试,BI)