题意:给你一个n行m列的格子,问你放1*2的木块有多少种放法。
思路:dp[i][s] 表示到第i行状态为s的方法数。 状态0表示这个位置是被下面那个竖着放的木块占了的,状态1表示是当前行横着放占了的。
暴力打出所有的匹配,然后状态转移就好啦,好像也能用轮廓线dp做,这个不会,明天补吧。。。。
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #define fi first 5 #define se second 6 #define mk make_pair 7 #define pii pair<int,int> 8 #define read(x) scanf("%d",&x) 9 #define sread(x) scanf("%s",x) 10 #define dread(x) scanf("%lf",&x) 11 #define lread(x) scanf("%lld",&x) 12 using namespace std; 13 14 typedef long long ll; 15 const int inf=0x3f3f3f3f; 16 const int INF=0x3f3f3f3f3f3f3f3f; 17 const int N=11; 18 const int M=12; 19 20 int n,m,up; 21 ll dp[M][1<<N]; 22 vector<int> s[1<<N]; 23 24 bool check(int s1,int s2) 25 { 26 if((s1|s2)!=up-1) 27 return false; 28 int cnt=0,all=n; 29 while(all--) 30 { 31 if(s2&1 && s1&1) 32 cnt++; 33 else 34 { 35 if(cnt&1) 36 return false; 37 cnt=0; 38 } 39 s2>>=1; s1>>=1; 40 } 41 if(cnt&1) 42 return false; 43 return true; 44 } 45 void init(){ 46 if(m>n) swap(n,m); 47 up=1<<m; 48 49 memset(dp,0,sizeof(dp)); 50 for(int i=0;i<up;i++) 51 s[i].clear(); 52 53 for(int i=0;i<up;i++) 54 for(int j=0;j<up;j++) 55 if(check(i,j)) 56 s[i].push_back(j); 57 } 58 int main() 59 { 60 while(scanf("%d%d",&n,&m)!=EOF && n && m) 61 { 62 init(); 63 64 dp[0][up-1]=1; 65 for(int i=0;i<n;i++) 66 { 67 for(int j=0;j<up;j++) 68 { 69 if(!dp[i][j]) 70 continue; 71 72 for(int u=0;u<s[j].size();u++) 73 { 74 int k=s[j][u]; 75 dp[i+1][k]+=dp[i][j]; 76 } 77 } 78 } 79 printf("%lld\n",dp[n][up-1]); 80 } 81 return 0; 82 } 83 /* 84 */