題目連結:http://poj.org/problem?id=2411
題意:
給你一個n*m的網格 (1<=n,m<=11) ,往裡面鋪1*2或2*1的磚塊,問你鋪完這個網格有多少種不同的方法。
題解:
表示狀態:
dp[state][i] = num of ways at ith row
(1)當前鋪到了第i行
(2)在鋪第i行之前,第i行已經被佔的格子狀態為state
如何轉移:
對於當前第i行的第j列處,有三種情況:
(1)豎著鋪。i+1行的第j個位置會被佔,在這一行佔用了一個寬度,接下來該在第j+1列鋪。
(2)橫著鋪。對i+1行沒有影響,在這一行佔用了兩個寬度,接下來該在j+2列鋪。
(3)已經被佔。只能不鋪,對i+1行沒有影響,接下來該在第j+1列鋪。
所以在求dp之前先暴搜出在一行上的每個狀態state鋪完之後下一行的狀態,存到vector中。
轉移:列舉每一行i,當前行的state,以及當前state能夠轉移的狀態nex。
dp[nex][i+1] += dp[state][i]
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <vector> 5 #define MAX_N 15 6 #define MAX_S (1<<12) 7 8 using namespace std; 9 10 int n,m; 11 long long dp[MAX_S][MAX_N]; 12 vector<int> shift[MAX_S]; 13 14 void dfs(int col,int state,int nex) 15 { 16 if(col==m) 17 { 18 shift[state].push_back(nex); 19 return; 20 } 21 if((state>>col)&1) 22 { 23 dfs(col+1,state,nex); 24 return; 25 } 26 dfs(col+1,state,nex|(1<<col)); 27 if(col+1<m && !((state>>(col+1))&1)) dfs(col+2,state,nex); 28 } 29 30 int main() 31 { 32 while(cin>>n>>m) 33 { 34 if(n==0 && m==0) break; 35 for(int state=0;state<(1<<m);state++) 36 { 37 shift[state].clear(); 38 } 39 for(int state=0;state<(1<<m);state++) 40 { 41 dfs(0,state,0); 42 } 43 memset(dp,0,sizeof(dp)); 44 dp[0][0]=1; 45 for(int i=0;i<n;i++) 46 { 47 for(int state=0;state<(1<<m);state++) 48 { 49 if(dp[state][i]) 50 { 51 for(int j=0;j<shift[state].size();j++) 52 { 53 int nex=shift[state][j]; 54 dp[nex][i+1]+=dp[state][i]; 55 } 56 } 57 } 58 } 59 cout<<dp[0][n]<<endl; 60 } 61 }