天天看點

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;