題目鏈結
在乙個給定形狀的棋盤(形狀可能是不規則的)上面擺放棋子,棋子沒有區別。要求擺放時任意的兩個棋子不能放在棋盤中的同一行或者同一列,請程式設計求解對於給定形狀和大小的棋盤,擺放k個棋子的所有可行的擺放方案c。
輸入含有多組測試資料。每組資料的第一行是兩個正整數,n k,用乙個空格隔開,表示了將在乙個n*n的矩陣內描述棋盤,以及擺放棋子的數目。 n <= 8 , k <= n
當為-1 -1時表示輸入結束。
隨後的n行描述了棋盤的形狀:每行有n個字元,其中 # 表示棋盤區域, . 表示空白區域(資料保證不出現多餘的空白行或者空白列)。
對於每一組資料,給出一行輸出,輸出擺放的方案數目c (資料保證c<2^31)。sample input
2 1sample output#..#
4 4…#
…#..#…
#…-1 -1
2題目分析:輸入棋盤的大小和棋子數,然後輸入棋盤,#為可落點,問有幾種行列都不同的擺放方法任意的兩個棋子不能放在棋盤中的同一行或者同一列,說明每行每列最多只有乙個,dfs的原理還沒理解透徹,但是我能想到的就是用dfs的引數代表行數,然後跑乙個for迴圈跑列數,這樣把兩個維度都跑一遍1
就像洛谷全排列那題鏈結
dfs引數代表的是本層查詢到的數字是第幾(陣列計數0開始還是通俗計數1開始)個,往往我們為了元素不能重複,需要有個bool陣列來記錄選取與否,而且可能會有乙個附加條件,像本題就是只有n個棋子,這樣才有了第二個維度;
也就是說,既然決定用dfs做題,分析到目前就要考慮兩點:
1、弄清楚dfs的引數代表什麼,不要搜的時候不明意義的瞎搜一通,至少除錯的時候知道當前狀態
2、考慮有沒有限制維度,決定是否在dfs的for迴圈中加入if判斷句
把部分**貼出來,等會再把完全體貼出來
if
(time== n)
if(k == n+1)
第一條對應著乙個dfs裡的if和return:,就是k=n+1那條,這樣決定了
dfs的搜尋層數,因為這個return我習慣叫搜尋區間溢位
第二條對應著time那條,決定了搜尋不溢位的情況下何時停止搜尋(這個因素不加說明n==區間大小,本題是棋盤總行數,也就是有幾行就有幾個棋子)
條件寫完了,那麼:
接下來是搜尋的具體實現部分
for
(int i =
1; i <= n; i++)}
//不管有沒有適合的*都不選擇該行或者沒有合適落點
dfs(k +1)
;
跑迴圈是為了按依次列數搜尋本行元素,其實每到一行還有乙個選不選擇的問題,舉個最容易理解的例子,如果一共8行全是#,但我只有7個棋子,就必然只有7行棋子能被選,也就是說,每一行都有棋子,說明能被選,但是從沒被選的那行思考,一共有8種可能,畢竟8行總要有一行不被選,也就是說,遇到一行,我們的思維應該是這樣:
那麼**完全版就可以出來了:
#include
#include
using
namespace std;
typedef
long
long ll;
int n, n;
ll sum;
int time;
//被選擇的行數
char s[10]
[10];
bool jud[10]
;//判斷對應列是否已經占用
void
dfs(
int k)
if(k == n+1)
for(
int i =
1; i <= n; i++)}
//不管有沒有適合的*都不選擇該行
dfs(k +1)
;}intmain()
dfs(1)
;//行數
cout << sum << endl;
}return0;
}
順便貼上一組簡單資料的gif**以便了解程式執行過程
POJ 1321 棋盤問題
time limit 1000ms memory limit 10000k total submissions 7007 accepted 3390 description 在乙個給定形狀的棋盤 形狀可能是不規則的 上面擺放棋子,棋子沒有區別。要求擺放時任意的兩個棋子不能放在棋盤中的同一行或者同一列...
poj 1321 棋盤問題
棋盤問題 time limit 1000ms memory limit 10000k total submissions 15365 accepted 7600 description 在乙個給定形狀的棋盤 形狀可能是不規則的 上面擺放棋子,棋子沒有區別。要求擺放時任意的兩個棋子不能放在棋盤中的同一...
POJ 1321 棋盤問題
找到第乙個有 的行開始回溯就可以了 include include using namespace std const int maxn 9 char board maxn maxn bool c maxn int ans,n,k void backtracking int curi,int cnt...