poj2411 DP压缩

来源:互联网 发布:骑士cms人才系统 编辑:程序博客网 时间:2024/05/17 23:36

高中就用PASCAL写过,但现在忘了,只记得是2进制状态压缩,却始终想不用如何具体维护两个状态的转移。

于是乎,参考了别人的代码,看到一种表示方法是:0表示横向(必然两个0连续),1表示纵向,(另外DP时1特指向下凸,)那么放满一行的state数是有限的,且远小于2^w,如果状态j对应statej可以从状态k推过来,那一定有k& ~statej == 0,(此处注意理解,是关键,若k对应r位上是1,则statej上也为1,取反在and则为0,若k上连续两个0,则statej对应连续两个0,取反再and则为11,故成立。)

#include <iostream>#include <fstream>#include <algorithm>#include <cstring>using namespace std;#define N 11#define M 2048long long f[N+5][M+5];int state[M+5];int h,w,js,sum;void dfs(int pos,int data){    if (pos==w) {        state[js++]=data;        return ;    }    if (pos+2<=w) dfs(pos+2,data);    dfs(pos+1,data+(1<<pos));}void DP(){    memset(f,0,sizeof(f));    for (int i=0;i<js;i++){        f[0][state[i]]=1;    }    for (int i=1;i<h;i++)        for (int j=0;j<js;j++)            for (int k=0;k<sum;k++){                if (f[i-1][k] && !(k&(~state[j])))                    f[i][state[j]-k]+=f[i-1][k];            }}int main(){    freopen("data.in","r",stdin);    //freopen("data.out","w",stdout);    cin>>h>>w;    while (!(h==0 && w==0)){          sum=1;          for (int i=0;i<w;i++) sum*=2;          js=0;          dfs(0,0);          DP();          printf("%I64d\n",f[h-1][0]);          cin>>h>>w;    }    return 0;}


原创粉丝点击