Description
在一個給定形狀的棋盤(形狀可能是不規則的)上面擺放棋子,棋子沒有區別。
要求擺放時任意的兩個棋子不能放在棋盤中的同一行或者同一列。請編程求解對於給定形狀和大小的棋盤,擺放k個棋子的所有可行的擺放方案C。
Input
輸入含有多組測試數據。
每組數據的第一行是兩個正整數,n,k,用一個空格隔開,表示了將在一個n∗n的矩陣內描述棋盤,以及擺放棋子的數目。
當爲−1 −1時表示輸入結束。
隨後的n行描述了棋盤的形狀:每行有n個字符,其中 # 表示棋盤區域, . 表示空白區域(數據保證不出現多餘的空白行或者空白列)。
Output
對於每一組數據,給出一行輸出,輸出擺放的方案數目C。
Sample Input 1
2 1
#.
.#
4 4
…#
…#.
.#…
#…
-1 -1
Sample Output 1
2
1
Hint
n<=8,k<=n
數據保證C <2^31
Time Limit
1000MS
Memory Limit
256MB
分析:題意爲求所有棋子擺放方案數,可知此題用深搜。撰寫搜索代碼的關鍵,在於理清楚搜索的單位,即空間狀態——能區分出每個結點的因素、進行搜索的邏輯在數據上的體現。此題中空間狀態不妨設爲:擺放在棋盤第幾行、還有幾個棋子未擺放。同時,此題的特別之處在於棋盤上的一行或多行可以不擺棋子,這時的空間狀態只變化行數,不變化剩餘棋子數。
參考代碼:
#include<stdio.h>
int n,k;//棋盤尺寸,棋子數目
int ans;//擺放方案數
char map[9][10];//描述棋盤的內容
bool vis[9];//記錄棋盤裏已經被佔用的列
//當前擺放棋盤第幾行,當前還有幾個棋子未擺放
void dfs(int now,int last)
{
if(last==0){//沒有剩餘棋子,都擺放完了
ans++;//找到一種擺放方案
return;
}
if(now>n){//當前方案不合法,回退,重新搜索
return;
}
//按列枚舉
for(int j=1;j<=n;j++)
{//是空白區域或者已經被佔用
if(map[now][j]=='.'||vis[j]) continue;
vis[j]=true;//標記
dfs(now+1,last-1);//擺下一行,棋子數減1
vis[j]=false;//回溯
}
//這一行沒有擺棋子,到下一行去擺
dfs(now+1,last);
return;
}
int main()
{
while(1)
{
scanf("%d%d",&n,&k);
if(n==-1&&k==-1) break;
for(int i=1;i<=n;i++)
{
scanf("%s",&map[i][1]);
}
ans=0;//答案清零
for(int i=0;i<9;i++)
{//標記數組也清零
vis[i]=0;
}
dfs(1,k);//開始搜索
printf("%d\n",ans);
}
return 0;
}