POJ 1321 棋盤問題

2021-07-15 11:47:12 字數 2010 閱讀 4093

在乙個給定形狀的棋盤(形狀可能是不規則的)上面擺放棋子,棋子沒有區別。要求擺放時任意的兩個棋子不能放在棋盤中的同一行或者同一列,請程式設計求解對於給定形狀和大小的棋盤,擺放k個棋子的所有可行的擺放方案c。

輸入含有多組測試資料。

每組資料的第一行是兩個正整數:n,

k(0n≤8)

,用乙個空格隔開,表示了將在乙個n×

n 的矩陣內描述棋盤,以及擺放棋子的數目。

當為-1 -1時表示輸入結束。

隨後的n行描述了棋盤的形狀:每行有n個字元,其中#表示棋盤區域,.表示空白區域(資料保證不出現多餘的空白行或者空白列)。

對於每一組資料,給出一行輸出,輸出擺放的方案數目c (資料保證

c<231

)。

21#.

.#44...

#..#.

.#..

#...

-1 -1

2

1

基本的路線就是搜尋了,同八皇后問題類似,利用回溯法暴力搜尋即可。

本題的剪枝條件較為簡單,在判定是否落子的時候滿足以下情形之一的即可剪枝:

所在位置為.表示此處不能落子。

與已落棋子位於同一行或同一列。

已落棋子等於k。

當剪枝越少時意味著搜尋演算法代價越高,即當棋盤上沒有.全是#的時候可以得到答案的上界: f(

n,k)

=akn

ckn=

n!n!

(n−k

)!(n

−k)!

k!即最終答案。

但搜尋演算法的代價不止於此,在每個點要判斷是否要剪枝需要付出額外的代價。

將棋盤以0-1鄰接矩陣的形式來儲存可以在很小的常數時間內判斷乙個給定的(行、列)元組,這個位置是否可落子。(bool board[n][n];)

按行搜尋,可以保證棋子不在同一行。

儲存列是否被占用的情況即可在很小的常數時間內判斷乙個給定的列是否已經被使用,維護這個值的正確性也只需要乙個很小的常數時間。(bool iscolumnused[n])

不需要在每個case之前初始化board, iscolumnused,要保證第乙個case 之前iscolumnused全為false,程式可以保證iscolumnused在case 結束時復原。 f

(n,k

) 關於 n 遞增: f(

n,k)

f(n−

1,k)

=n2(

n−k)

2>1

f(n,

k)關於 k 先遞增後遞減,其遞增區間: f(

n,k+

1)f(

n,k)

=(n−

k)2k

+1>1k

2−(2

n+1)

k+n2

−1>0k

<2n

+1−4

n+5−

−−−−

√2或k

>2n

+1+4

n+5−

−−−−

√2>n(舍

去) 即f

(n,k

) 關於

k 在 (0

,2n+

1−4n

+5√2

)上遞增,在(2

n+1−

4n+5

√2,n

] 上遞減。

則maxf(

n,k)

=max

對於 0

n≤8 ,

maxf(n

,k)=

maxf(8

,k)=

max=f(

8,6)

=564480

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...