POJ 1321 棋盤問題【DFS/回溯】
阿新 • • 發佈:2018-06-17
des 重點 freopen getchar 回溯 return 問題 形狀 tor
隨後的n行描述了棋盤的形狀:每行有n個字符,其中 # 表示棋盤區域, . 表示空白區域(數據保證不出現多余的空白行或者空白列)。
Output
這裏有兩種情況,由於只要放k個棋子,且有些行不能放棋子。處理當前行的時候有兩種狀態,一是在當前行放棋子,二是不放棋子。放棋子就判斷是否有相同列,不放棋子則直接深搜下一行。
而dfs的辦法也有幾種,常見的有
1.參數只有一個i表示當前搜索行;
2.參數有i表示當前搜索行和cnt表示已填充的棋子數 ;
3.參數有i表示當前搜索行和cnt表示已填充的棋子數 ,雙重循環遍歷,不用考慮放不放
【代碼】:
棋盤問題
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 62164 Accepted: 29754
Description
在一個給定形狀的棋盤(形狀可能是不規則的)上面擺放棋子,棋子沒有區別。要求擺放時任意的兩個棋子不能放在棋盤中的同一行或者同一列,請編程求解對於給定形狀和大小的棋盤,擺放k個棋子的所有可行的擺放方案C。
Input
輸入含有多組測試數據。
每組數據的第一行是兩個正整數,n k,用一個空格隔開,表示了將在一個n*n的矩陣內描述棋盤,以及擺放棋子的數目。 n <= 8 , k <= n
當為-1 -1時表示輸入結束。
Output
對於每一組數據,給出一行輸出,輸出擺放的方案數目C (數據保證C<2^31)。
Sample Input
2 1
.
.#
4 4
...#
..#.
.#..
...
-1 -1
Sample Output
2
1
Source
蔡錯@pku
【分析】:因為棋子的數量k比棋盤數目n少,那麽可能有些棋盤區不用放置棋子。這是重點,易錯點。
然後這道題和n皇後有點像,要求同一行、同一列不能放棋子,那麽我們一行到下一行逐行搜索,是自然遍歷下來的,不用管;就用一個數組標記列放沒放棋子,沒放過並且是棋盤區就標記可以放,然後回溯(還原現場)進行下一次嘗試。
而dfs的辦法也有幾種,常見的有
1.參數只有一個i表示當前搜索行;
2.參數有i表示當前搜索行和cnt表示已填充的棋子數 ;
3.參數有i表示當前搜索行和cnt表示已填充的棋子數 ,雙重循環遍歷,不用考慮放不放
【代碼】:
#include<cstdio> #include<string> #include<cstdlib> #include<cmath> #include<iostream> #include<cstring> #include<set> #include<queue> #include<algorithm> #include<vector> #include<map> #include<cctype> #include<stack> #include<sstream> #include<list> #include<assert.h> #include<bitset> #include<numeric> #define debug() puts("++++") #define gcd(a,b) __gcd(a,b) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define fi first #define se second #define pb push_back #define sqr(x) ((x)*(x)) #define ms(a,b) memset(a,b,sizeof(a)) #define sz size() #define be begin() #define pu push_up #define pd push_down #define cl clear() #define lowbit(x) -x&x #define all 1,n,1 #define rep(i,n,x) for(int i=(x); i<(n); i++) #define in freopen("in.in","r",stdin) #define out freopen("out.out","w",stdout) using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> P; const int INF = 0x3f3f3f3f; const LL LNF = 1e18; const int maxn = 1e6; const int maxm = 10; const double PI = acos(-1.0); const double eps = 1e-8; const int dx[] = {-1,1,0,0,1,1,-1,-1}; const int dy[] = {0,0,1,-1,1,-1,1,-1}; const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int n,k; char a[maxm][maxm],v[maxm]; int cnt,tot; void dfs(int i) { if(cnt==k) //當計數器達到k(擺放棋子的數目),不管結果如何都結束了 { tot++; return ; } if(i>=n) return ; for(int j=0;j<n;j++) { if(!v[j] && a[i][j]=='#') { v[j]=1; cnt++; dfs(i+1); v[j]=0; cnt--; } } dfs(i+1); //i行不放棋子 } int main() { while(~scanf("%d%d",&n,&k)) { tot=cnt=0; ms(a,0); if(n==-1&&k==-1) break; getchar(); // for(int i=0;i<n;i++) gets(a[i]); dfs(0); cout<<tot<<endl; } } /* 2 1 #. .# 4 4 ...# ..#. .#.. #... */
POJ 1321 棋盤問題【DFS/回溯】