題目
西元 2185 年,地球人終於有能力征服其他有生物的星球,
不過卻受到該星球生物的反擊。於是科學家們發明了一種「最終兵器 X」,
它能自動攻擊左上、上、右上、右、右下、下、左下、左等八個方向的敵人,
只要在地圖上放上幾台,就可以不費吹灰之力消滅敵人。
輸入說明
輸入第一行會有一個正整數 T,表示總共有幾筆測資。
每筆測資有一個正整數 N (4<=N<=12),代表要放 N 台的最終兵器 X。
輸出說明
針對每筆輸入請輸出每種可能的排法,因為每列只能放一個,
故只要輸出每列的最終兵器 X 是放在第幾行就可以了,
請依序輸出第一列、第二列、…第 N 列的位置。
順序越前面數字越小越好。
想法
這題其實就是把八皇后變成 N 皇后。
我們可以先開一個陣列int queen[15];
,
存放「每一列」要在「哪一欄」放皇后,
因此哪一列就是陣列的 index,
而在該 index 的值就是指在那一列的哪一欄放皇后。
(這個部分其實輸出說明算是有提示到)
再來開始建造遞迴函數。
1 | void solve(int n) { |
我遞迴的想法是:solve(n)
代表現在要放第n
個皇后了。
先不管會被其他皇后吃掉的情形,
我們有N
個位置可以放皇后(0 ~ N - 1),
所以先放一個for
迴圈,
到迴圈裡面再判斷該位置能不能放皇后,
如果可以的話,就紀錄那個位置,
也就是第n
個皇后(第n
列)放在第i
欄,
寫作queen[n] = i;
。
記錄下來之後我們就可以開始考慮放下一個皇后,
所以呼叫solve(n + 1);
。
現在回到判斷格子能不能放的問題。
1 | int conflict(int n, int t) { |
這個conflict
函數的參數n
, t
,
其實可以理解為棋盤的 x 和 y,
或是說第n
個皇后放在第t
欄;
而它的回傳值是0
或1
(其實它是個布林值,只是我懶得include
):0
代表第n
個皇后可以放在第t
欄;1
代表第n
個皇后不能放在第t
欄。
先來一個for
迴圈,
因為要和先前放的所有皇后比較。
第三行的if (t == queen[i]) return 1;
,
是要看它和第i
個皇后會不會位在同一欄
(由於我們宣告queen[]
的想法已經不會讓皇后位在同一列了,
所以不需要再另外判斷皇后會不會在同一列)。
第四行的(n - i)
和(t - queen[i])
可以理解為 x 和 y 的位移,當它們的絕對值一樣,
代表它們位在同一條斜線上。
最後回到solve
函數,
當我們遞迴到solve(N)
時就代表已經放完棋子了
(因為棋子會在第0
到N - 1
列),
該停止了,不然會一直遞迴下去。
所以加上 2 ~ 8 這幾行,讓它輸出,就完成這題了。
1 | void solve(int n) { |
完整程式碼:
1 |
|