POJ 2441 Arrange the Bulls 状态压缩DP

                 恩恩,最近在练习状态压缩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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值