POJ 2441 Arrange the Bulls 状态压缩DP

来源:互联网 发布:木马盗号软件 编辑:程序博客网 时间:2024/05/22 18:56

                 恩恩,最近在练习状态压缩DP,这道题目一开始就想出状态转移方程了,可是爆了MLE。。。一下子还真的没有想到怎么去优化这个东西。。。

                 状态压缩的推导方法和POJ 1321还有POJ 3254 的差不多 这里是POJ 1321 的解题报告:http://blog.csdn.net/good_night_sion_/article/details/52432629

                 最后看了别人的题解,发现别人使用的滚动数组解决这个问题的,确实滚动数组可以用来优化,然后还发现了一种连滚动数组都不需要的解法,其实我感觉就和背包的问题的空间优化差不多,只是披上了状态压缩的外衣。。恩,果然还是需要多多练习才是。

                 这是没有用滚动数组的写法,76ms过掉了

#include<cstdio>#include<cstring>using namespace std;int n,m,arr[25][25],board[(1<<20)+10],lim,ans;int main(){   // printf("%lld\n",sizeof(board));    while(scanf("%d%d",&n,&m)!=EOF){        for(int i=1;i<=n;++i){            scanf("%d",&arr[i][0]);            for(int j=1;j<=arr[i][0];++j)                scanf("%d",&arr[i][j]);        }        if(n>m){            printf("0\n");            continue;        }        lim=1<<m;        board[0]=1;        for(int i=1;i<=n;++i){            for(int j=lim-1;j>=0;--j){                if(board[j]==0)continue;                for(int k=1;k<=arr[i][0];++k)                if(((1<<arr[i][k]-1)&j)==0)                board[j|(1<<arr[i][k]-1)]+=board[j];                board[j]=0;            }        }        for(int i=0;i<lim;++i)        ans+=board[i];        printf("%d\n",ans);ans=0;        memset(board,0,sizeof(int)*lim);    }    return 0;}

            这下是用了滚动数组的写法,我用了500ms过掉了,我觉得应该还可以优化,但是POJ挂掉了,没办法验证。。
#include<cstdio>#include<cstring>using namespace std;int n,m,arr[25][25],board[2][(1<<20)+10],bitcount(int x),lim,ans;int main(){   // printf("%lld\n",sizeof(board));    while(scanf("%d%d",&n,&m)!=EOF){        for(int i=1;i<=n;++i){            scanf("%d",&arr[i][0]);            for(int j=1;j<=arr[i][0];++j)                scanf("%d",&arr[i][j]);        }        if(n>m){            printf("0\n");            continue;        }        lim=1<<m;        board[0][0]=1;        for(int i=1;i<=n;++i){            for(int j=0;j<lim;++j){                if(board[1-(i&1)][j]==0)continue;                for(int k=1;k<=arr[i][0];++k)                if(((1<<arr[i][k]-1)&j)==0)                board[i&1][j|(1<<(arr[i][k]-1))]+=board[1-(i&1)][j];            }        }        for(int i=0;i<lim;++i)        if(bitcount(i)==n)        ans+=board[n&1][i];        printf("%d\n",ans);ans=0;        for(int i=0;i<=1;++i)        memset(board[i],0,sizeof(int)*lim);    }    return 0;}int bitcount(int x){    int times=0;    for(;x;x>>=1)if(x&1)++times;    return times;}

              注意!代码里面的有一个if(board[x]==0)continue;这句代码很重要!可以明显的减少很多不必要的操作,滚动数组没有想到这个优化的情况下时间爆长。。。我用了3700ms+才过掉了,,要是卡时间就完蛋了。



1 0
原创粉丝点击