問題描述:八皇后問題是數學家高斯於1850年提出的,這是一個典型的回溯算法的問題。八皇后問題的大意如下:
國際象棋的棋盤有8行8列共64個單元格,在棋盤上擺放8個皇后,使其不能互相攻擊,也就是說任意兩個皇后都不能處於同一行、同一列或同一斜線上。問總共共有多少種擺放方法,每一種擺放方式是怎樣的。
目前,數學上可以證明八皇后問題總共有92種解。
思路:保證8個皇后不能互相攻擊,即保證每一橫行、每一豎行、每一斜行最多一個皇后。
①不能在同一行,同一列②以及同一對角線(左右)
(1)對於①不能在同一行,同一列:
意思即,每一橫行、每一豎行都只有一個皇后。我們暫時先撇開第②個條件,將8*8棋盤標上座標。我們討論其中的一種解法(我們規定橫縱座標都從1開始):
- - - - - - - Q
- - - Q - - - -
Q - - - - - - -
- - Q - - - - -
- - - - - Q - -
- Q - - - - - -
- - - - - - Q -
- - - - Q - - -
如果用座標表示就是:(1,8) (2,4) (3,1) (4,3) (5,6) (6,2) (7,7) (8,5)
將橫座標按次序排列,縱座標就是8/4/1/3/6/2/7/5。縱座標就是1~8的一個全排列。
規定橫座標就是從1-8,按照行遞增去給某列排皇后。相當於給每一行分別賦值滿足題中條件的列數。
(2)對於②以及同一對角線(左右):你知道的,兩個點之間連線的斜率絕對值爲1或者-1即爲同一斜行,充要條件是|x1-x2|=|y1-y2|(兩個點的座標爲(x1,y1)(x2,y2))。我們在輸出的時候進行判斷,任意兩個點如果滿足上述等式,則判爲失敗,不輸出。我們這裏把行當做,橫座標,把列當做縱座標。
綜上,其實這個問題可以簡化爲,找出縱座標等同於找出符合以上兩個條件(①和②)的1~n的全排列(實則是縱座標的值)。因爲,橫座標是1-n,不會變。
下面就好說了,如果還不知道全排列的思路,點擊下面這個:
生成1~n的全排列思路及代碼
該題基本和全排列是一樣的,只不過多了一個判定條件,那就是左右對角線。
下面附上AC代碼:
#include<cstdio>
#include<cmath>
const int maxn=11;
int count=0;
//P爲當前排列,hashTable記錄整數x是否已經在P中
int n,P[maxn] ,hashTable[maxn] = {false};
void generateP(int index)//index爲給第index行排皇后
{
if(index==n+1)
{
count++;
return ;
}
for(int x=1;x<=n;x++)//給第index行,第x列排皇后
{
if(hashTable[x]==false)//第x列還沒有皇后
{
bool flag=true;// flag表示當前皇后不會和之前的皇后衝突
for(int pre=1;pre<index;pre++)// 遍歷index之前行的皇后
{//第index行的皇后的列號爲x,第pre行皇后的列號爲P[pre]
if(abs(index-pre)==abs(x-P[pre])) //橫座標之差==縱座標之差
{
flag=false;// 與之前的皇后在一條對角線,衝突
break;
}
}
if(flag)//如果可以把皇后放在第index行
{
P[index]=x;//令第index行皇后的列數爲x
hashTable[x]=true;//第x列已經被佔用
generateP(index+1);//遞歸處理第index+1行以及之後行的皇后(index+1~n)
hashTable[x]=false;//遞歸完畢,還原第x列爲佔用狀態
}
}
}
}
int main()
{
n=8;
generateP(1);
printf("%d\n",count);
return 0;
}
建議看這個題之前看一下,全排列,其實是一毛一樣的。只要和全排列聯繫上,這個題也就不是什麼事情啦。加油!