天天看点

POJ [ 八皇后问题 ]——递归练习dfs

总时间限制: 
10000ms
内存限制: 
65536kB
描述
在国际象棋棋盘上放置八个皇后,要求每两个皇后之间不能直接吃掉对方。
输入
无输入。
输出
按给定顺序和格式输出所有八皇后问题的解(见Sample Output)。
样例输入
样例输出
No. 1
1 0 0 0 0 0 0 0 
0 0 0 0 0 0 1 0 
0 0 0 0 1 0 0 0 
0 0 0 0 0 0 0 1 
0 1 0 0 0 0 0 0 
0 0 0 1 0 0 0 0 
0 0 0 0 0 1 0 0 
0 0 1 0 0 0 0 0 
No. 2
1 0 0 0 0 0 0 0 
0 0 0 0 0 0 1 0 
0 0 0 1 0 0 0 0 
0 0 0 0 0 1 0 0 
0 0 0 0 0 0 0 1 
0 1 0 0 0 0 0 0 
0 0 0 0 1 0 0 0 
0 0 1 0 0 0 0 0 
No. 3
1 0 0 0 0 0 0 0 
0 0 0 0 0 1 0 0 
0 0 0 0 0 0 0 1 
0 0 1 0 0 0 0 0 
0 0 0 0 0 0 1 0 
0 0 0 1 0 0 0 0 
0 1 0 0 0 0 0 0 
0 0 0 0 1 0 0 0 
No. 4
1 0 0 0 0 0 0 0 
0 0 0 0 1 0 0 0 
0 0 0 0 0 0 0 1 
0 0 0 0 0 1 0 0 
0 0 1 0 0 0 0 0 
0 0 0 0 0 0 1 0 
0 1 0 0 0 0 0 0 
0 0 0 1 0 0 0 0 
No. 5
0 0 0 0 0 1 0 0 
1 0 0 0 0 0 0 0 
0 0 0 0 1 0 0 0 
0 1 0 0 0 0 0 0 
0 0 0 0 0 0 0 1 
0 0 1 0 0 0 0 0 
0 0 0 0 0 0 1 0 
0 0 0 1 0 0 0 0 
No. 6
0 0 0 1 0 0 0 0 
1 0 0 0 0 0 0 0 
0 0 0 0 1 0 0 0 
0 0 0 0 0 0 0 1 
0 1 0 0 0 0 0 0 
0 0 0 0 0 0 1 0 
0 0 1 0 0 0 0 0 
0 0 0 0 0 1 0 0 
No. 7
0 0 0 0 1 0 0 0 
1 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 1 
0 0 0 1 0 0 0 0 
0 1 0 0 0 0 0 0 
0 0 0 0 0 0 1 0 
0 0 1 0 0 0 0 0 
0 0 0 0 0 1 0 0 
No. 8
0 0 1 0 0 0 0 0 
1 0 0 0 0 0 0 0 
0 0 0 0 0 0 1 0 
0 0 0 0 1 0 0 0 
0 0 0 0 0 0 0 1 
0 1 0 0 0 0 0 0 
0 0 0 1 0 0 0 0 
0 0 0 0 0 1 0 0 
No. 9
0 0 0 0 1 0 0 0 
1 0 0 0 0 0 0 0 
0 0 0 1 0 0 0 0 
0 0 0 0 0 1 0 0 
0 0 0 0 0 0 0 1 
0 1 0 0 0 0 0 0 
0 0 0 0 0 0 1 0 
0 0 1 0 0 0 0 0 
...以下省略      

==========================    

        首先本题坑点:结果要按列输出。

        其次对于八皇后问题做个好几次了,其中复杂点的地方就是对角线的限制,但每次做都是用自己的方法写的,自己写的麻烦一点,所以这次翻了一下题解,学到了以规律代替数字条对角线的方法,而且这样也就没有“多指向”的问题了。

首先,还是附上按自己思路写的代码:

#include<bits/stdc++.h>
using namespace std;
int king[100][100]; //把数组开成整形,因为一个位置可能被多个位置所限制;
bool memor[100][100];
int k=0;
void signn(int x,int y)
{
    king[x][y]++;
    for(int i=1;i<=8;++i)
        if(i!=x)king[i][y]++;
    for(int i=x,j=y;i<=8&&j<=8;++i,++j)
        if(i!=x&&j!=y)king[i][j]++;
    for(int i=x,j=y;i>=1&&j>=1;--i,--j)
        if(i!=x&&j!=y)king[i][j]++;
    for(int i=x,j=y;i<=8&&j>=1;++i,--j)
        if(i!=x&&j!=y)king[i][j]++;
    for(int i=x,j=y;i>=1&&j<=8;--i,++j)
        if(i!=x&&j!=y)king[i][j]++;
}
void f_signn(int x,int y)
{
    king[x][y]--;
    for(int i=1;i<=8;++i)
        if(i!=x)king[i][y]--;
    for(int i=x,j=y;i<=8&&j<=8;++i,++j)
        if(i!=x&&j!=y)king[i][j]--;
    for(int i=x,j=y;i>=1&&j>=1;--i,--j)
        if(i!=x&&j!=y)king[i][j]--;
    for(int i=x,j=y;i<=8&&j>=1;++i,--j)
        if(i!=x&&j!=y)king[i][j]--;
    for(int i=x,j=y;i>=1&&j<=8;--i,++j)
        if(i!=x&&j!=y)king[i][j]--;
}
void printff()    //本题坑点;
{
    k++;
    cout<<"No. "<<k<<endl;
    for(int i=1;i<=8;++i)
    {
        for(int j=1;j<=8;++j)
            cout<<memor[j][i]<<" ";
        cout<<endl;
    }
}
void search(int x)
{
    if(x>8)
    {
        printff();
        return ;
    }
    for(int i=1;i<=8;++i)
    {
        if(king[x][i]==0)
        {
            memor[x][i]=1;
            signn(x,i);
            search(x+1);
            memor[x][i]=0;
            f_signn(x,i);


        }
    }
}
int main()
{
    search(1);
    return 0;
}
           

然后,来看一下经典解法:

#include<bits/stdc++.h>
using namespace std;
bool d[101],b[101],c[101];//b标记该列,c标记对角线“/”方向,d标记“\”方向;
int k=0,a[101][101];
void search(int);
void printff();
int main()
{
    search(1);
    return 0;
}
void search(int i)
{
    if(i>8)
    {
        printff();
        return ;
    }
    for(int j=1;j<=8;++j)
        if((!b[j])&&(!c[i+j])&&(!d[i-j+7]))
        {
            a[i][j]=1;
            b[j]=1;
            c[i+j]=1;      //标记“/”方向;
            d[i-j+7]=1; //标记“\”方向,另外+7是为了避免出现负数;
            search(i+1);
            b[j]=0;
            c[i+j]=0;
            d[i-j+7]=0;
            a[i][j]=0;

        }
}
void printff()
{
    k++;
    cout<<"No. "<<k<<endl;
    for(int i=1;i<=8;++i)
    {
        for(int j=1;j<=8;++j)
        {
            cout<<a[j][i]<<" ";//按列输出;
        }
        cout<<endl;
    }
}
           

The end;