-
作者 : 卿篤軍
本文討論了八皇后問題的三種解決方案:
一、枚舉法
二、回溯法(遞歸版)
三、回溯法(非遞歸版)
本來這些代碼是以前編寫好的,沒有發表,由於最近又學習到了八皇后問題,自己整理了一下發表了出來!
首先、說明一下何爲八皇后問題,我也不去谷歌了,直接簡單的說明一下:
八皇后問題,就是在一個8*8的平面棋盤上,要求你擺放8個棋子,要求:這8個棋子不能有2個在同一行,也不能有2個在同一列,同時一條斜線上面也不能有2個~~~~
比如:4*4的棋盤,你可以這樣擺放(4皇后問題):
以上圖爲參照,我們分析一下,要使棋子不衝突,那算法要如何寫?<喎�"/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+ztLDx72rtv7OrMr91+m9tc6q0rvOrMr91+mjrLKi08PPwsPm1eLW1re9yr3AtLHqvMfG5dfTo7o8L3A+CjxwPsq+wP2juiBhWzFdID0gMiCjrLHtyr612jHB0LXaMtDQ09DG7NfToaM8L3A+CjxwPmFbMl0gPSA0IKOsILHtyr612jLB0LXaNNDQ09DG7NfToaM8L3A+CjxwPmFbM10gPSAxIKOsILHtyr612jPB0LXaMdDQ09DG7NfToaM8L3A+CjxwPmFbNF0gPSAzIKOsse3KvrXaNMHQtdoz0NDT0Mbs19OhozwvcD4KPHA+PGJyPgo8L3A+CjxwPrrDo6y909fFt9bO9rPlzbvL47eouMPI57rOseDQtKO6o6iz5c27y+O3qKO6vs3Kx9PDwLTF0LbPwuTG5dfTzrvWw8rHt/HT68bky/zG5dfTs+XNu6OpPC9wPgo8cD6/ycTcs/bP1rXEvLjW1rPlzbvH6b/2o7o8L3A+CjxwPjGjqbXa0rvQ0NPQwb249sbl19OjrNOmuMPKx9Xi0fmx7cq+o7phWzFdID0gMSwgYVsyXSA9IDEsse3KvrXa0rvB0LrNtdq2/sHQtcS12tK70NC2vNPQxuXX06Oo1N3H0rK7v7zCxzMsNMHQo6mhozwvcD4KPHA+MqOp1ve21L3Hz9/Jz9PQMrj2xuXX06Os06a4w8rH1eLR+bHtyr6jumFbMV0gPSAyLCBhWzJdID0gMyyx7cq+tdrSu8HQtdq2/tDQo6y12rb+wdC12sj90NDOu9bDyc/T0Mbl19OhozwvcD4KPHA+M6OptM621L3Hz9/Jz9PQMrj2xuXX06Os06a4w8rH1eLR+bHtyr6jumFbM10gPSA0LCBhWzRdID0gMyyx7cq+tdrI/cHQtdrLxNDQo6y12svEwdC12sj90NDOu9bDyc/T0Mbl19OhozwvcD4KPHA+PHN0cm9uZz7XotLio7qyu7/JxNzU2sHQyc+z9s/Ws+XNu6Os0vLOqqOsztLDx8rHsLTB0LDat8W1xKGjvLSjurXa0rvB0MnPsNq3xdK7uPajrMi7uvPU2rXatv7B0MnPsNq3xS4uLi4utdrI/cHQo6zDv8HQsNq3xdK7uPbG5dfToaM8L3N0cm9uZz48L3A+CjxwPs/Cw+ax4NC0tPrC66O6o6g8c3Ryb25nPse/tfejus/Cw+az9s/WtcSyu7ncysdpu7nKx2qx7cq+tcS2vMrHwdCjurXaacHQo6y12mrB0Dwvc3Ryb25nPqOpPC9wPgo8cD48c3Ryb25nPtDQs+XNu6O6PC9zdHJvbmc+PC9wPgo8cD7K18/Io6y87LLitdrSu9DQtcQxLTjB0KOsyse38bPlzbuho8i7uvO87LLitdq2/tDQLi4uLi4uLi4uLi61sci7xuTKtbXa0rvB0LK70OjSqrzssuKjqNLyzqqw2rfFtdrSu7j2xuXX07XEyrG68qOsxuXFzMnPu7nDu9PQxuXX06Ossru/ycTcs+XNu6OpPC9wPgo8cD48L3A+CjxwcmUgY2xhc3M9"brush:java;">for (int i = 1; i <= 8; ++i) //檢測1~8行{for (int j = 1; j <= 8; ++j) //檢測1~8列{if (a[i] == a[j])return "衝突";}}return "不衝突";對角線衝突:
這裏稍微用數學分析一下,用i,j表示當前正在檢測的兩列(i外層for循環,j內層for循環),那麼a[i] ,a[j] 的值就分別表示當前檢測列棋子擺放的位置即行(每列只有1個棋子)。
如果兩個棋子對角線衝突(正反對角線衝突),則必然有:
轉化爲代碼:
123456789for
(
int
i =
1
; i <=
8
; ++i)
//檢測1~8行
{
for
(
int
j =
1
; j <=
8
; ++j)
//檢測1~8列
{
if
((a[i] - a[j] == i - j) || (a[i] - a[j] == j - i))
//對角線衝突
return
"衝突"
;
}
}
return
"不衝突"
;
優化整理後的衝突判斷代碼就出爐了,如下所示:123456789//位置衝突算法
bool Chongtu(
int
a[],
int
n)
//a[]位置數組,n皇后個數
{
for
(
int
i =
2
; i <= n; ++i)
//i:位置
for
(
int
j =
1
; j <= i-
1
; ++j)
//j:位置
if
((a[i] == a[j]) || (abs(a[i]-a[j]) == i-j))
//1:在一行;2:在對角線上
return
false
;
//衝突
return
true
;
//不衝突
}
好了,該說明的都說明了,現在編寫第一個八皇后代碼~~~~
枚舉法:
思想:八重枚舉,枚舉出所以擺放的情況(不管合理不合理),然後到第八層for裏面判斷當前枚舉出來的情況是否合理~~~~
12345678910111213141516171819202122232425262728293031323334353637383940414243444546#include <stdio.h>
#include <math.h>
//位置衝突算法
bool Chongtu(
int
a[],
int
n)
//a[]位置數組,n皇后個數
{
int
i =
0
, j =
0
;
for
(i =
2
; i <= n; ++i)
//i:位置
for
(j =
1
; j <= i-
1
; ++j)
//j:位置
if
((a[i] == a[j]) || (abs(a[i]-a[j]) == i-j))
//1:在一行;2:在對角線上
return
false
;
//衝突
return
true
;
//不衝突
}
//八皇后:枚舉算法
void
Queens8()
{
int
a[
9
] = {
0
};
//用於記錄皇后位置:(第0行0列我們不用)。如:a[3] = 4;表示第3列第4行位置有皇后
int
i =
0
,count =
0
;
//用於計數
for
(a[
1
] =
1
; a[
1
] <=
8
; ++a[
1
])
for
(a[
2
] =
1
; a[
2
] <=
8
; ++a[
2
])
for
(a[
3
] =
1
; a[
3
] <=
8
; ++a[
3
])
for
(a[
4
] =
1
; a[
4
] <=
8
; ++a[
4
])
for
(a[
5
] =
1
; a[
5
] <=
8
; ++a[
5
])
for
(a[
6
] =
1
; a[
6
] <=
8
; ++a[
6
])
for
(a[
7
] =
1
; a[
7
] <=
8
; ++a[
7
])
for
(a[
8
] =
1
; a[
8
] <=
8
; ++a[
8
])
{
if
(!Chongtu(a,
8
))
//如果衝突,則繼續枚舉
continue
;
else
{
printf(
"第%d情況:"
,++count);
for
(i =
1
; i <=
8
; ++i)
printf(
"%d "
,a[i]);
//打印某種情況
printf(
"\n"
);
}
}
}
//主函數
int
main()
{
Queens8();
return
0
;
}</math.h></stdio.h>
回溯法(遞歸版):1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950#include <stdio.h>
#include <math.h>
int
a[
9
] = {
0
};
int
n =
8
, count =
0
;
//位置衝突算法
bool Chongtu(
int
a[],
int
n)
//a[]位置數組,n皇后個數
{
int
i =
0
, j =
0
;
for
(i =
2
; i <= n; ++i)
//i:位置
for
(j =
1
; j <= i-
1
; ++j)
//j:位置
if
((a[i] == a[j]) || (abs(a[i]-a[j]) == i-j))
//1:在一行;2:在對角線上
return
false
;
//衝突
return
true
;
//不衝突
}
//八皇后問題:回溯算法(遞歸版)
void
Queens8(
int
k)
//參數k:遞歸擺放第k個皇后
{
int
i =
0
;
if
(k > n)
//k>n:即k>8表示最後一個皇后擺放完畢
{
printf(
"第%d種情況:"
,++count);
for
(i =
1
; i <= n; ++i)
printf(
"%d "
,a[i]);
//打印情況
printf(
"\n"
);
}
else
//8個皇后未全部擺放完畢
{
for
(i =
1
; i <= n; ++i)
//擺放第k個皇后時(轉下一行)
{
//依次從列頂端開始搜索,一直到列底端,直到找到合適位置,如果未找到,自動返回上層遞歸(回溯)
a[k] = i;
if
(Chongtu(a,k))
//不衝突
Queens8(k+
1
);
//遞歸擺放下一個皇后
}
}
return
;
}
//主函數
int
main()
{
Queens8(
1
);
//參數1:表示擺放第1個皇后
return
0
;
}
</math.h></stdio.h>
回溯法(非遞歸版):12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758#include <stdio.h>
#include <math.h>
//位置衝突算法
bool Chongtu(
int
a[],
int
n)
//a[]位置數組,n皇后個數
{
int
i =
0
, j =
0
;
for
(i =
2
; i <= n; ++i)
//i:位置
for
(j =
1
; j <= i-
1
; ++j)
//j:位置
if
((a[i] == a[j]) || (abs(a[i]-a[j]) == i-j))
//1:在一行;2:在對角線上
return
false
;
//衝突
return
true
;
//不衝突
}
//八皇后問題:回溯法(非遞歸)
void
Queens8()
{
int
n =
8
;
//8個皇后
int
count =
0
;
//記錄當前第幾情況
int
a[
9
] = {
0
};
//存放皇后位置,如:a[2] = 4;表示第2列第4行有一個皇后(a[0]不用)
int
i =
0
,k =
1
;
//初始化k爲第一列
a[
1
] =
0
;
//初始化a[1] = 0
while
(k >
0
)
//k==0時:表示擺放第1個皇后就超過了列底部(即已經找完所有情況)
{
a[k] +=
1
;
//a[k]位置,擺放一個皇后
while
((a[k] <= n) && (!Chongtu(a,k)))
//如果a[k](即皇后擺放位置)沒有到列最底部,且擺放衝突。
a[k] +=
1
;
//將皇后列下移一位
if
(a[k] <= n)
//皇后擺放位置沒有到達列最底部
{
if
(k == n)
//k==n表示,8列皇后全部擺放完畢
{
printf(
"第%d種情況:"
,++count);
for
(i =
1
; i <= n; ++i)
//打印情況
printf(
"%d "
,a[i]);
printf(
"\n"
);
}
else
//皇后還未擺放完畢
{
k +=
1
;
//繼續擺放下一列
a[k] =
0
;
//此行初始化a[k] = 0;表示第k列,從第一行開始擺放皇后
}
}
else
//回溯:當a[k]>8進入else,表示在第k列中沒有找到合適的擺放位置
k -=
1
;
//回溯到k-1步:k表示第幾個皇后,a[k]表示第k個皇后擺放的位置
}
return
;
}
//主函數
int
main()
{
Queens8();
return
0
;
}</math.h></stdio.h>
八皇后問題(回溯法&枚舉法)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.