题目链接: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 }