N皇后問題
Problem Description
在N*N的方格棋盤放置了N個皇后,使得它們不相互攻擊(即任意2個皇后不允許處在同一排,同一列,也不允許處在與棋盤邊框成45角的斜線上。
你的任務是,對於給定的N,求出有多少種合法的放置方法。
Input
共有若干行,每行一個正整數N≤10,表示棋盤和皇后的數量;如果N=0,表示結束。
Output
共有若干行,每行一個正整數,表示對應輸入行的皇后的不同放置數量。
Sample Input
1
8
5
0
Sample Output
1
92
10
解題思路
這道題主要考察的是回溯的思想。
我們以5個皇后爲例講這道題
首先我們把第一個皇后放在(1,1)處。那麼很顯然,第一行第一列以及(i,i)點所處位置即45度斜線方向都不可以放皇后了
我們看下一個皇后應該放在那裏。(先看列再看行),很顯然第一列不可以放了,第二列第一行即(1,2)不可以。第二列第二行(2,2)可以。那麼我們放第二個皇后,同時按要求把他鎖在的行列和45度角方向畫上斜線
同上面的步驟一樣,我們再找下一個皇后位置(2,3)。
我們可以看出來,這樣放過(2,3)之後就在也放不下下一個皇后了。所以這種方法一共只能放三個皇后。是不合法的。
此時我們就用到了回溯。就是恢復到上一個放的皇后(2,2)哪裏。重新找下一個皇后,而且我們知道在找到(2,3)皇后之前我們已經判斷過哪些點了,所以我們緊接着判斷(2,3)後面的點(2,4)就可以了,並且我們一定要把(2,3)位置恢復成沒有標記過的點。
找到下一個皇后(第三個皇后)位置爲(5,3).
找第四個皇后位置(2,4)
找到第五個皇后位置
我們可以看出5個皇后已經都安排好位置了。我們再重新從空表開始,確定第一個皇后的位置就是(2,1)。按以上步驟找就可以了
代碼
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
int n;
int erwei[12][12]; //標記是否可以放皇后
int hang[12]; //標記行是否可以放皇后
int lie[12]; //標記列是否可以放皇后
int sum; //一共有幾種方法
int table[12]; //幾個皇后對應的有幾種方法
bool check(int i, int j)
{
int s,t;
if(hang[i]) return false; //這一行已有皇后,該位置不合法。
if(lie[j]) return false; //這一列已有皇后,該位置不合法。
for(s=i-1,t=j-1;s>=0&&t>=0;s--,t--) //判斷左上角有沒有皇后。
{
if(erwei[s][t]) return false;
}
for(s=i+1,t=j+1;s<n&&t<n;s++,t++) //判斷右下角有沒有皇后。
{
if(erwei[s][t]) return false;
}
for(s=i-1,t=j+1;s>=0&&t<n;s--,t++) //判斷右上角有沒有皇后。
{
if(erwei[s][t]) return false;
}
for(s=i+1,t=j-1;s<n&&t>=0;s++,t--) //判斷左下角有沒有皇后。
{
if(erwei[s][t]) return false;
}
return true;
}
void dfs(int j)
{
if(j==n)
{
sum++;
return;
}
for(int i=0;i<n;i++)
{
bool flag=check(i,j); //判斷該位置是否可以放皇后
if(flag) //如果該位置可以放
{
erwei[i][j]=1;
hang[i]=1;
lie[j]=1;
dfs(j+1); //判斷下一列
erwei[i][j]=0;
hang[i]=0;
lie[j]=0;
}
}
}
int main()
{
for(int i=1;i<=10;i++)
{
memset(erwei,0,sizeof(erwei));
memset(hang,0,sizeof(hang));
memset(lie,0,sizeof(lie));
n=i;
sum=0;
dfs(0);
table[i]=sum;
}
while(scanf("%d",&n))
{
if(n==0)
break;
printf("%d\n",table[n]);
}
return 0;
}