1. 程式人生 > >POJ-1321棋盤問題

POJ-1321棋盤問題

題目原連結

棋盤問題
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 62010   Accepted: 29682

Description

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

Input

輸入含有多組測試資料。 
每組資料的第一行是兩個正整數,n k,用一個空格隔開,表示了將在一個n*n的矩陣內描述棋盤,以及擺放棋子的數目。 n <= 8 , k <= n 
當為-1 -1時表示輸入結束。 
隨後的n行描述了棋盤的形狀:每行有n個字元,其中 # 表示棋盤區域, . 表示空白區域(資料保證不出現多餘的空白行或者空白列)。 

Output

對於每一組資料,給出一行輸出,輸出擺放的方案數目C (資料保證C<2^31)。

Sample Input

2 1
#.
.#
4 4
...#
..#.
.#..
#...
-1 -1

Sample Output

2
1

題意:輸入兩個整數n,k,輸入-1,-1時表示輸入結束,n代表n*n的棋盤,k代表目標放棋子的數目,棋盤的形狀不確定,但是#表示可以放,. 表示不可以放,問放k個棋子一共有多少种放法。

注意:判斷是否滿足條件和判斷是否越界的先後順序;

#include<iostream>
#include<cstring>
using namespace std;
int n,k,cnt,t;
int vis[8];
char maze[8][8];
void dfs(int x)
{
	//注意這兩個if,順序不能顛倒,否則結果比實際滿足要求的數量少1;
	/*原因:程式執行到這裡時,已經從上一層滿足條件的情況跳到了下一層了,
	所以此時的t是上一層滿足條件的t的數量,而x是目前這一層的情況,還沒有判斷x是否越界和
	判斷是否可以放棋子,所以,這個t要優先判斷是否滿足了題意,然否再判斷x是否越界;
	*/
	if(t==k)
	{
		cnt++;
		return ;
	}
	if(x>=n)
		return ;
	for(int j=0;j<n;j++)
	{
		if(maze[x][j]=='#'&&!vis[j])//滿足要求的條件是:這個位置是#,這個位置沒有被標記過;
		{
			vis[j]=1;//對當前符合要求的這層的這一列標記;
			t++;	//放上一個棋子,棋子數量+1;
			dfs(x+1);
			vis[j]=0;//返回到了上一層,對這一層解除標記;
			t--;	//因為返回到了上一層,所以要減去這一層放上的棋子;
		}
	}
	dfs(x+1);//這一層沒有符合要求的,只能跳過這層了,所以,層數增加,棋子數量不增加;
}
int main()
{
	while(cin>>n>>k&&n<=8&&k<=n&&n!=-1&&k!=-1)
	{
		cnt=0;//記錄滿足情況的數目;
		t=0;//記錄放入棋子的個數;
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				cin>>maze[i][j];
		memset(vis,0,sizeof(vis));//也可以這樣寫:memset(vis,0,n*n);
		dfs(0);//從第一層開始搜尋第一個適合放棋子的地方;
		cout<<cnt<<endl;
	}
	return 0;
}
/*dfs的另一種寫法:每次傳遞兩個引數;

注意把main()中的dfs改為dfs(0,0);

void dfs(int x,int t)
{
	if(t==k)
	{
		cnt++;
		return ;
	}
	if(x>=n)
		return ;
	for(int j=0;j<n;j++)
	{
		if(maze[x][j]=='#'&&!vis[j])
		{
			vis[j]=1;
			dfs(x+1,++t);//注意t,一定要寫成++t,t++和t+1都不對,因為我們的目的是讓t在呼叫dfs之前就增加1,如果不這樣寫達不到目標效果;
			vis[j]=0;
			t--;
		}
	}
	dfs(x+1,t);
}
*/