hihocoder1044(状压DP)

题目链接

看博客一律都说很简单,还有各种骚操作。体验好差。

考虑第到第i个位置的情况,我们只需要知道前面m-1个位置的情况就可以了。所以将前面m-1加上i这m个位置压缩为一个状态,然后可以求出取了几个位置,如果取了超过q个就不再考虑。
考虑小于等于q的情况。基本的状态转移方程就是
dp[i][j]=max(dp[i1][j>>1],dp[i1][j/2+(1<<m1)]); d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j >> 1 ] , d p [ i − 1 ] [ j / 2 + ( 1 << m − 1 ) ] ) ;
这里 j/2+(1<<m1) j / 2 + ( 1 << m − 1 ) 是表示这m个数之前的那一个数是1的情况,同理j/2就是代表之前的那一个数是0的情况。
然后就分为两种情况,就是第i位是否取的情况,直接将压缩后的状态j&1就可以判断当前j状态是否取了第i位(搞不懂为什么那么多人选择了不容易明白的方式。),如果取了第i位上面的方程就要加上第i位的垃圾数。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,q;
int num[1005],dp[1005][(1 << 10) + 5];
int main()
{
    while(~scanf("%d %d %d",&n,&m,&q))
    {
        for (int i = 1; i <= n; i++)
        {
            scanf("%d",&num[i]);
        }
        memset(dp,0,sizeof dp);

        int maxn = (1 << m);
        for (int i = 1; i  <= n; i++)
        {
            for (int j = 0; j < 1 << (m); j++)
            {
                int temp = 0,x = j;
                while(x)
                {
                    temp += x&1;
                    x>>=1;
                }
                if(temp > q)continue;
                if(j&1)dp[i][j] = max(dp[i - 1][j>>1],dp[i - 1][j/2 + (1<<m-1)]) + num[i];
                else dp[i][j] = max(dp[i - 1][j / 2],dp[i - 1][j/2 + (1<<m-1)]);
            }
        }
        int ans = 0;
        for (int i = 0; i < (1<<(m)); i++)
        {
            if(dp[n][i] > ans)
                ans = dp[n][i];
        }
        printf("%d\n",ans);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值