POJ 2411 位压缩dp

参考:http://blog.csdn.net/woshi250hua/article/details/7952496

状态转移方程:dp[i+1][k]=sum(dp[i][j]);对于每一行,因为最多有11列,所以最多有2^11=2048个状态,由于一行的状态只受前一行状态的影响,因此关键是j如何才能转向k。本题目采用的是插头dp,如果某个位置为0表示该位置是一个插头,可以将木块竖着放。否则,必须有连续偶数个1才行。

边界条件:可以将第0行预设为全是1,终态为最后一行全部为1,dp[h][2^w-1]。

程序中,枚举每个状态是否可行。另,交换h,w是的h<=w会使速度更快。

//11217061	c00h00g	2411	Accepted	580K	860MS	G++	937B	2013-01-28 18:06:34
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int h,w;
__int64 dp[12][2048];

int isOk(int from,int to){
    for(int i=0;i<w;i++){
        int x=from&(1<<i);
        int y=to&(1<<i);
        if(!x&&!y) return 0;
        if(x&&y){
            i++;
            if(i==w) return 0;
            if((from&(1<<i))==0) return 0;
            if((to&(1<<i))==0) return 0;
        }
    }
    return 1;
}
int main(){
    while(scanf("%d%d",&h,&w)!=EOF){
        if(h==0&&w==0) break;
        if(h%2&&w%2) { printf("0\n");continue;}
        int Max=(1<<w)-1;
        memset(dp,0,sizeof(dp));
        dp[0][Max]=1;
        for(int i=0;i<h;i++)
            for(int j=0;j<=Max;j++)
                if(dp[i][j])
                    for(int k=0;k<=Max;k++)
                        if(isOk(j,k))
                            dp[i+1][k]+=dp[i][j];
        printf("%I64d\n",dp[h][Max]);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值