POJ 2411 位压缩dp

来源:互联网 发布:js 调用windows程序 编辑:程序博客网 时间:2024/05/22 12:06

参考: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会使速度更快。

//11217061c00h00g2411Accepted580K860MSG++937B2013-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;}



原创粉丝点击