zoukankan      html  css  js  c++  java
  • HDU 1565 方格取数(简单状态压缩DP)

    http://acm.hdu.edu.cn/showproblem.php?pid=1565

    对于每一个数,取或者不取,用0表示不取,1表示取,那么对于每一行的状态,就可以用一个二进制的数来表示。比如5的二进制为101,就表示取第一个数,不取第二个数,取第三个数。

    将符合要求的状态保存下来,什么是符合要求的呢?即二进制数中不存在相邻的1(110,011都是不符合要求的)。可以用移位并按位与的办法来判断,举个例子:110左移一位为011 ,110&011 = 1,不符合要求;101左移一位为010,101&010=0,符合要求,这是判断同一行时的方法。

    判断上下两行,只需将上下两行的状态按位与即可。(PS:在纸上写写,和容易就能看出来)

    然后枚举每一行的状态和上一行的状态,找出不与上一个状态冲突的情况,然后计算,选择当前状态的最大值

    AC

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    int status[20000];//存状态
    int mp[25][25];
    int d[25][20000];//d[i][j]表示第i行第j种状态时的最大和(这时的最大和是1~i行所能取得的最大和)
    int n;
    ///将符合要求的状态保存下来,即没有两个一相邻的情况
    int init(int n)
    {
        int M=0;
        for(int i=0 ; i<n ; i++)
        if((i&(i>>1))==0)///不相邻
        status[M++] = i;
        return M;
    }
    ///计算该状态的和
    int cal(int x,int t)
    {
        int sum=0,j=n-1;
        while(t)
        {
            if(t&1)///最后为是1
            sum+=mp[x][j];
            j--;
            t >>= 1;
        }
        return sum;
    }
    int main( )
    {
    
        while(scanf("%d",&n)!=EOF)
        {
             if(n == 0)//加上这句用C++提交能过,没这句C++就过不了,但G++能,不知道为啥
            {
                printf("0
    ");
                continue;
            }
            int M = init(1<<n);///初始化,找到状态一有多少
            memset(d,0,sizeof(d));
            for(int i=0 ; i<n ; i++)
            for(int j=0 ; j<n ; j++)
            scanf("%d",&mp[i][j]);
            for(int i=0 ; i<M ; i++)
            d[0][i]=cal(0,status[i]);
            for(int i=1 ; i<n ; i++)///第i行
            {
                for(int j=0 ; j<M ; j++)///枚举第i行状态
                {
                    int t=cal(i,status[j]);
                    for(int k=0 ; k<M ; k++)///枚举上一行的状态,即第i-1行  
                    {
                        if(status[j]&status[k])///上一行和这一行存在上下相邻的1 
                        continue;
                        d[i][j]=max(d[i-1][k]+t,d[i][j]);
                    }
                }
            }
            int ans=0;
            for(int i=n-1 , j=0 ; j<M ; j++)
                ans=max(d[i][j],ans);
            printf("%d
    ",ans);
    
        }
        return 0;
    }
    View Code
  • 相关阅读:
    BZOJ2219数论之神——BSGS+中国剩余定理+原根与指标+欧拉定理+exgcd
    Luogu 3690 Link Cut Tree
    CF1009F Dominant Indices
    CF600E Lomsat gelral
    bzoj 4303 数列
    CF1114F Please, another Queries on Array?
    CF1114B Yet Another Array Partitioning Task
    bzoj 1858 序列操作
    bzoj 4852 炸弹攻击
    bzoj 3564 信号增幅仪
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/9132788.html
Copyright © 2011-2022 走看看