E - Maximum Sum -状压DP

  • E - Maximum Sum

     Gym - 101853E 
  • 题意:choose a subset of the grid's cells, such that their summation is as maximal as possible.
  • 限制: there are no two adjacent cells in that subset. Two cells are considered adjacent if they are horizontal, vertical, or diagonal neighbors.
  • 随便选择一些数要求和最大
  • 取数要求:不能上下、左右、主对角、副对角、直接相邻。
  • n为16利用二进制枚举出一行合法状态,现在只考虑一行的限制之后左右相邻非法
  • 所以二进制枚举一行中所有的状态合法的保存即可(枚举x时判断 x<<1&x与x>>1&x)
  • dp数组第一维代表第几行第二维代表第几个单独一行合法的二进制状态。
  • 后面的每一行的状态肯定是这里面的,但是会有列,对角线的要求所以三个for第一个for枚举接下来的行
  • 第二个for枚举当前行选择的那个单独一行合法状态第三个for枚举上一行合法的状态对这两行进行列关系与对角关系的判断
  • (当前行为c1上一行为c2,c1&c2||c1&(c2<<1)||c1&(c2>>1)这都是非法状态即上下相邻主对角相邻副对角相邻直接continue)
  • 这样进行dp更新最大值即可。其中getsum是对相应的合法二进制状态对应到真实图上去取值求和
  • ——by  SDUT-QYN
  • #include<bits/stdc++.h>
    using namespace std;
    #define maxn 20
    #define mxx (1<<16)+10
    #define ll long long
    int t,n,mmp[maxn][maxn],sum;
    int dp[maxn][mxx],ans,m,c1,c2,one[mxx];
    bool judge(int x)
    {
        if(x&(x<<1))
            return false;
        if(x&(x>>1))
            return false;
        return true;
    }
    int getsum(int row,int cur)
    {
        int ret=0;
        for(int i=0; i<n; i++)
            if(cur&(1<<i))
                ret+=mmp[row][i];
        return ret;
    }
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            ans=sum=0;
            memset(one,0,sizeof(one));
            memset(dp,0,sizeof(dp));
            scanf("%d",&n);
            for(int i=0; i<n; i++)
                for(int j=0; j<n; j++)
                    scanf("%d",&mmp[i][j]);
            m=(1<<n);
            for(int i=0; i<=m; i++)
                if(judge(i))
                {
                    one[sum]=i;
                    dp[0][sum]=getsum(0,i);
                    ans=max(ans,dp[0][sum]);
                    sum++;
                }
            for(int r=1; r<n; r++)
                for(int i=0; i<sum; i++)
                {
                    c1=one[i];
                    for(int j=0; j<sum; j++)
                    {
                        c2=one[j];
                        if(c1&c2||c1&(c2>>1)||c1&(c2<<1))continue;
                        dp[r][i]=max(dp[r][i],dp[r-1][j]+getsum(r,c1));
                        ans=max(dp[r][i],ans);
                    }
                }
            printf("%d\n",ans);
        }
        return 0;
    }
    

     

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值