poj 2411 Mondriaan's Dream

题目连接:http://poj.org/problem?id=2411

这个题目用状态压缩DP很容易理解,主要是先预处理,预处理就是把第一行合法状态置1。然后枚举第i行和第i-1行的状态,在不矛盾的情况下可以相加。dp[i][k]表示第第i行状态为k时的总种数。所以最后只要输出dp[row-1][0]即可,这样保证最后一行保证填满而且不会在伸出。自己的方法简单易懂但是不够优化,时间复杂度为o(row*(1<<col)*(1<<col)),后来看了别人的解题报告发现可以优化到O(row*(1<<col)*(可行状态数))这在时间上可以优化很多。

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

__int64 dp[12][1<<12];

int row,col;

bool isCan(int x){
    int i=0;
    while(i<col){
        if((1<<i)&x)i++;
        else{
            if((1<<(i+1))&x)return false;
            if(i==(col-1))return false;
            i+=2;
        }
    }
    return true;
}

void init(){
    memset(dp,0,sizeof(dp));
    for(int i=0;i<(1<<col);i++){
        if(isCan(i)){
            dp[0][i]=1;
        }
    }
}

int main(){
    while(scanf("%d%d",&row,&col)){
        if(row==0 && col==0)return 0;
        init();
        for(int i=1;i<row;i++){
            for(int k=0;k<(1<<col);k++){
                for(int j=0;j<(1<<col);j++){
                    if(k&j)continue;
                    if(isCan(k|j)){
                        dp[i][k]+=dp[i-1][j];
                    }
                }
            }
        }
        printf("%I64d\n",dp[row-1][0]);
    }
}

你可能感兴趣的:(poj 2411 Mondriaan's Dream)