zoukankan      html  css  js  c++  java
  • Mondriaan's Dream(poj2411)

    题意:求1*2的牌填满n*m的表格有多少种不同的方法;

    状态压缩dp

    (注:思路来自不知名的大神)

    用2进制的01表示不放还是放
    第i行只和i-1行有关
    枚举i-1行的每个状态,推出由此状态能达到的i行状态
    如果i-1行的出发状态某处未放,必然要在i行放一个竖的方块,所以我对上一行状态按位取反之后的状态就是放置了竖方块的状态。
    然后用搜索扫一道在i行放横着的方块的所有可能,并且把这些状态累加上i-1的出发状态的方法数,如果该方法数为0,直接continue。
    举个例子
    2 4
    1111
    1111
    状态可以由
    1100 0000 0110 0011 1111
    0000 0000 0000 0000 0000
    这五种i-1的状态达到,故2 4 的答案为5
     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 using namespace std;
     5 int n,m;
     6 long long add;
     7 long long dp[2][1<<12];
     8 void dfs(int i,int s,int cur)
     9 {
    10     if(cur==m) {dp[i][s]+=add;return;}
    11     dfs(i,s,cur+1);
    12     if(cur<m-1&&!(s&1<<cur)&&!(s&1<<(cur+1)))
    13         dfs(i,s|1<<cur|1<<(cur+1),cur+2);
    14 }
    15 int main()
    16 {
    17     while(scanf("%d%d",&n,&m),n+m)
    18     {
    19         if(n*m%2) {printf("0\n");continue;}
    20         int rt=(1<<m)-1;
    21         add=1;
    22         memset(dp,0,sizeof(dp));
    23         dfs(0,0,0);
    24         for(int i=1;i<n;i++)
    25         {
    26             memset(dp[i%2],0,sizeof(dp[1]));
    27             for(int j=0;j<=rt;j++) if(dp[(i-1)%2][j])
    28             {
    29                 add=dp[(i-1)%2][j];
    30                 dfs(i%2,~j&rt,0);
    31             }
    32         }
    33         printf("%I64d\n",dp[(n-1)%2][rt]);
    34     }
    35     return 0;
    36 }
  • 相关阅读:
    hdu 4963(中途相遇法)
    UVALive 6869(后缀数组)
    AC自动机小结
    poj 2409+2154+2888(Burnside定理)
    HUST 1569(Burnside定理+容斥+数位dp+矩阵快速幂)
    bunoj 34990(hash)
    CSU 1506(最小费用最大流)
    CF 514C(hash)
    lightoj 1297(三分)
    lightoj 1179(线段树)
  • 原文地址:https://www.cnblogs.com/qijinbiao/p/2684048.html
Copyright © 2011-2022 走看看