Mondriaan's Dream POJ - 2411 (状压DP)
题目链接:
Mondriaan's Dream
题目大意:就是给你一个n*m的矩阵,然后问你用2*1的矩阵和1*2的矩阵,有多少种方法能凑出来n*m的矩阵,在不会有重叠的前提下。
具体思路:状压dp,对于1*2的矩阵,我们将这个方块构成的两块都标记为1;对于2*1的矩阵,我们将上面那个方块标记为0,下面那个方块标记为1.然后在具体判断的过程中,先判断第一行,
011是合法的,01是非法的。。。就是1只能是相邻的为偶数个。然后接下来的若干行按位判断、
当(i,j)为0,(i-1,j)为0的时候,这种时候是非法的。
当(i,j)为0,(i-1,j)为1的时候,这种时候是合法。
当(i,j)为1,(i-1,j)为0的时候,这种时候是合法的。
当(i,j)为1,(i-1,j)为1的时候,并且(i,j+1)和(i-1,j+1)都为1,是合法的。
前三种情况都右跳一个,最后一种情况右跳两个。
具体的学习网址:https://blog.csdn.net/hopeztm/article/details/7841917
AC代码:
1 #include<iostream>
2 #include<stdio.h>
3 #include<cmath>
4 #include<cstring>
5 #include<string>
6 using namespace std;
7 # define inf 0x3f3f3f3f
8 # define ll long long
9 const int maxn = 2e5 +100;
10 const int N = (1ll<<11);
11 ll dp[12][N],n,m;
12 bool check(ll j)
13 {
14 ll i=0;
15 while(i<m)
16 {
17 if (( (1ll<<i) & j ) == 0 )
18 i++;
19 else if(i == m-1 || ((j & (1ll<<(i+1ll))) ==0))
20 {
21 return false;
22 }
23 else
24 {
25 i+=2;
26 }
27 }
28 return true;
29 }
30 bool judge(int pos_state,int head_state)
31 {
32 int i=m-1;
33 while(i>=0)
34 {
35 int pos1=(pos_state&(1<<i));
36 int pos2=(head_state&(1<<i));
37 if(!pos1&&!pos2){return false;}
38 if(!pos1&&pos2){i--;continue;}
39 if(pos1&&!pos2){i--;continue;}
40 if((i-1)>=0&&pos1&&pos2&&(pos_state&(1<<(i-1)))&&(head_state&(1<<(i-1)))){i-=2;continue;}
41 return false;
42 }
43 return true;
44 }
45 int main()
46 {
47 while(~scanf("%lld %lld",&n,&m)&&(n+m))
48 {
49 memset(dp,0,sizeof(dp));
50 if(m>n)
51 swap(n,m);
52 ll maxstate=(1ll<<m)-1;
53 for(ll j=0; j<=maxstate; j++)
54 {
55 if(check(j))
56 {
57 dp[0][j]=1;
58 }
59 }
60 for(ll i=1; i<n; i++)
61 {
62 for(ll j=0 ; j <= maxstate ; j++)
63 {
64 for(ll k=0; k <= maxstate ; k++)
65 {
66 if(judge(j,k))
67 {
68 dp[i][j]+=dp[i-1][k];
69 }
70 }
71 }
72 }
73 printf("%lld\n",dp[n-1][maxstate]);
74 }
75 return 0;
76 }