POJ2411 Mondriaan‘s Dream 状压DP

题意:

一个 n ∗ m n*m nm的棋盘放满 1 ∗ 2 1*2 12的小矩形,一共有多少种方案。

题解:

状压DP入门。在每一行的矩形只有3种情况:

  1. 横着的 1 ∗ 2 1*2 12矩形

  2. 竖着的 1 ∗ 2 1*2 12矩形,本行是上方

  3. 竖着的 1 ∗ 2 1*2 12矩形,本行是下方

简单分析可得,用一个 m m m位的二进制数表示本行矩形的放置。其中这位为 0 0 0代表着与下一行无关(1,3), 1 1 1代表着与下一行有关(2)。 F [ i ] [ j ] F[i][j] F[i][j]表示第 i i i行放置情形为 j j j时的方案数。

对于 F [ i − 1 ] [ k ] F[i-1][k] F[i1][k]转移到 F [ i ] [ j ] F[i][j] F[i][j]的条件为:

  • k & j = 0 k\&j=0 k&j=0,代表 k k k中1的下面均为 0 0 0
  • k ∣ j k|j kj二进制表示中每一段连续的 0 0 0都是偶数个。 k ∣ j k|j kj为1代表着竖着的矩形,既包括2,还有3。偶数个是保证1。

可以预处理出来m位二进制数中哪些连续的 0 0 0为偶数个。

易错:

不能一次预处理出来所有的,因为连续的 0 0 0的个数与位数有关!比如当 m = 7 m=7 m=7时, 0 0 0是不合法的;但是当 m = 8 m=8 m=8时,0是合法的。所以读取 m m m后根据 m m m大小预处理。

预处理也很巧。用 o d d odd odd表示是否存在奇数个连续的 0 0 0 c n t cnt cnt表示连续的 0 0 0是奇还是偶。如果这一位是 1 1 1 o d d ∣ = c n t , c n t = 0 odd|=cnt,cnt=0 odd=cnt,cnt=0,更新存不存在奇数个连续的 0 0 0,将 c n t cnt cnt初始化;如果不是1,那么 c n t ∧ = 1 cnt^{\wedge}=1 cnt=1,表示当前这段连续的 0 0 0是奇数还是偶数。二进制的每一位都遍历过后,如果最后一段是 0 0 0,那么此时 c n t cnt cnt还没有更新 o d d odd odd,因此 o d d ∣ c n t = = 1 odd|cnt==1 oddcnt==1时,说明有奇数个连续的 0 0 0,否则是合法的。

输出 F [ n ] [ 0 ] F[n][0] F[n][0],不是 F [ n ] [ m ] F[n][m] F[n][m]

AC代码:

#include <cstdio>
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define lep(i,a,b) for(int i=(a);i>=(b);i--) 
#define lepp(i,a,b) for(int i=(a);i>(b);i--)
#define pii pair<int,int>
#define pll pair<long long,long long>
#define mp make_pair
#define pb push_back 
#define fir first
#define sec second
#define All(x) x.begin(),x.end() 
#define ms(a,b) memset(a,b,sizeof(a)) 
#define INF 0x3f3f3f3f
#define INFF 0x3f3f3f3f3f3f3f3f
#define multi int T;scanf("%d",&T);while(T--) 
using namespace std;
typedef long long ll;
typedef double db;
const int N=(1<<11)+5;
const int mod=10007;
const db eps=1e-6;                                                                            
const db pi=acos(-1.0);
int n,m,zero2[N];
ll f[15][N];
int main(){
    #ifndef ONLINE_JUDGE
    freopen("D:\\work\\data.in","r",stdin);
    #endif
    // repp(i,0,1<<11){
    //     int cnt=0,odd=0;
    //     repp(j,0,11){
    //         if(i>>j&1) odd|=cnt,cnt=0;
    //         else cnt^=1;
    //     }
    //     zero2[i]=odd|cnt?0:1;
    // }
    f[0][0]=1;
    while(cin>>n>>m&&n){
        repp(i,0,1<<m){
            int cnt=0,odd=0;
            repp(j,0,m){
                if(i>>j&1) odd|=cnt,cnt=0;
                else cnt^=1;
            }
            zero2[i]=odd|cnt?0:1;
        }
        rep(i,1,n)
            repp(j,0,1<<m){
                f[i][j]=0;
                repp(k,0,1<<m){
                    if((j&k)==0&&zero2[j|k]) f[i][j]+=f[i-1][k];
                }
            }
        cout<<f[n][0]<<endl;
    }    
}

猜你喜欢

转载自blog.csdn.net/Luowaterbi/article/details/110912952