POJ2411 Mondriaan‘s Dream(状压dp,预处理)

传送门
这种放置类的状压dp一般是按行划分阶段.状态之间的转移一般依据题目给的限制.例如这题提供了2种1×2的方块.横放的方块对下一行是没有影响的,只有竖放的方块才能影响到下一行.所以我们用1来表示竖放方块的上半部分,用0表示其他状态.
再考虑不合法的状态,显然i-1和i行在第j列不能同时为1,可以直接用&来进行运算.还要注意的是如果第j列同时为0.说明至少有一行会横放方块.所以要有连续的偶数个0才可以放置.这一步用|来进行运算.
到这里复杂度还是有点大,因为我们要对|运算的结果进行判断是否都是连续的偶数个0.可以进行优化.提前把这些状态处理好.达到O(1)的判断时间.
如果要在一步进行优化的话,可以发现每行之间进行的匹配都是一样的,可以只存合法的转移达到进一步优化的目的(测试了一下会快大概一倍).
代码:

#pragma GCC optimize(2)
#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>

using namespace std;
const int N = 12;

inline void read(int &a){
    
    
    int x = 0,f=1;char ch = getchar();
    while(ch<'0'||ch>'9'){
    
    if(ch=='-')f=-1;ch=getchar();}
    while(ch<='9'&&ch>='0'){
    
    x=x*10+ch-'0';ch=getchar();}
    a = x*f;
}

LL dp[N][1<<N];
bool judge[1<<N];
int main(){
    
    
    int n,m;
    while(cin >> n >> m,n&&m){
    
    
        mem(dp,0);
        dp[0][0] = 1;
        fir(i,0,(1<<m)-1){
    
    
            int cnt = 0;
            bool f = 1;
            fir(j,0,m-1){
    
    
                int bit = (i >> j) & 1;
                if(bit){
    
    
                    if(cnt % 2){
    
    
                        f = 0;
                        break;
                    }
                    cnt = 0;
                }
                else{
    
    
                    cnt++;
                }
            }
            if(cnt%2) f= 0;
            judge[i] = f;
        }
        fir(i,1,n){
    
    
            fir(j,0,(1<<m)-1){
    
    
                fir(k,0,(1<<m)-1){
    
    
                    if(!(j & k) && judge[j|k]){
    
    
                        dp[i][j] += dp[i-1][k];
                    }
                }
            }
        }
        cout << dp[n][0] << endl;
    }
    
    return 0;
}    

猜你喜欢

转载自blog.csdn.net/weixin_45590210/article/details/108054633