POJ 1321 棋盤問題(DFS板子題,簡單搜索練習)


棋盤問題

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 44012   Accepted: 21375

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

Source

題目鏈接:http://poj.org/problem?id=1321
分析:

這個題目的大意是給定一個棋盤和給定我們需要擺放的棋子的數目,然后問我們有幾種擺放方式。首先我們可以明確這是一個深度搜索的題目,與八皇后問題相似。我們建立一個函數DFS用來累計可行的方案數,我們走過一列我們就把它標記下來下次的時候就不可以再擺放在這一列(因為題目要求不可以將棋子擺放在同一行和同一列)

然后就從下一行開始尋找可行的地方,直到我們擺放的棋子數與我們被要求擺放的棋子數相同時,我們就將方案數進行一次++,然后在進行遞歸下去。

DFS板子題,還在熟練中,爭取達到閉着眼睛三分鍾敲出板子!

此題我每一步給出詳細解釋,新手學習,大神見諒!

下面給出詳解代碼:

 

 1 #include<iostream>
 2 #include <algorithm>
 3 #include <stdio.h>
 4 #include <string.h>
 5 using namespace std;
 6 int visit[20];
 7 char mp[20][20];
 8 int ans;//ans表示方案數
 9 int k;//k表示棋子數目
10 int n;//n表示棋盤的大小
11 int DFS(int x,int y)
12 {
13     if(y>=k)//判斷是否棋子已經用完,如果用完,記錄方案數加1,然后直接返回0
14     {
15         ans++;
16         return 0;
17     }
18     for(int i=x;i<n;i++)
19     {
20         for(int j=0;j<n;j++)
21         {
22             if(!visit[j]&&mp[i][j]=='#')//標記數組僅僅標記某一列上是否有棋子,因為每次遞歸下一列,所以每一列不會有沖突,只需判斷這一列上是否有其他棋子
23             {
24                 visit[j]=true;//如果該位置該列沒被標記且為棋盤,那么在這里放上棋子,並標記,
25                 DFS(i+1,y+1);//搜索下一列
26                 visit[j]=false;//還要注意修改標記后遞歸回來要及時復原
27             }
28         }
29     }
30     return 0;
31 }
32 int main()
33 {
34     while(cin>>n>>k)
35     {
36         if(n==-1&&k==-1)
37             break;
38         memset(visit,false,sizeof(visit));
39         memset(mp,false,sizeof(mp));
40         for(int i=0;i<n;i++)
41             cin>>mp[i];
42         ans=0;
43         DFS(0,0);
44         cout<<ans<<endl;
45     }
46     return 0;
47 }

 多年以后重寫此題,想出了另外一種解決辦法!

題目意思很明了,其中'#'可以放棋子,'.'不能,並且同一行或同一列不能放兩個棋子,對於數據一游兩種放法('*'代表放的棋子)
*. 
#.
#.  
.*
對於數據二只有一種情況
...*
..*.
.*..
*...
這題只需要深搜,每次從上一個放棋子地方的下一行開始尋找可以放棋子的地方,
當發現該點時,記錄行數,並更新棋盤,將於此點同行同列的都更新為'.',
如果找不到,則返回,當把所有棋子都放上去的時候,則找到一個接,計數+1,就這樣進行搜索,可以保證AC 
 1 #include <iostream>
 2 using namespace std;
 3 struct p{
 4     char s[10][10];//棋盤 
 5     int beforerow;//上一個棋子的行數 
 6 };
 7 //st表示開始搜索的棋子所在的那一行,resnum表示剩余可放的棋子數 
 8 int n,resnum;//n表示當前的棋盤大小為n*n,k表示可放的總棋子數
 9 int ans;//擺放的所有可能數
10 void DFS(p temp,int resnum)
11 {
12     if(resnum==0)//如果剩余棋子數量等於0,說明所有棋子都已經放好了,答案數+1返回 
13     {
14         ans++;
15         return;
16     }
17     //否則就得從當前棋子的下一行開始搜索
18     //並且我們知道棋子數k大於行數n的情況顯然是不存在的,有了肯定是無解情況,這里就不需要討論這個問題 
19     int i,j;
20     for(i=temp.beforerow+1;i<=n-resnum;i++)
21     {
22         for(j=0;j<n;j++)
23         {
24             if(temp.s[i][j]=='#')
25             {
26                 p temp1;
27                 temp1=temp;
28                 temp1.beforerow=i;//記下改點的行數 
29                 int k;
30                 for(k=i+1;k<n;k++)//更新棋盤 
31                 {
32                     temp1.s[k][j]='.';
33                 }
34                 DFS(temp1,resnum-1);//放好一個棋子繼續搜 
35             }
36         }
37     } 
38 }
39 int main()
40 {
41     while(cin>>n>>resnum)
42     {
43         
44         if(n==-1&&resnum==-1)
45             break;
46         ans=0;
47         p temp;
48         temp.beforerow=-1;//此時還未放棋子,初始化為-1 
49         for(int i=0;i<n;i++)
50         {
51             cin>>temp.s[i];
52         }
53         DFS(temp,resnum);
54         cout<<ans<<endl;
55     }
56     return 0;
57 }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM