UPC-5842 硬币游戏IV(DP)

这里写图片描述

题目意思有表述不准确的地方,每次可以选择两枚编号相差K的硬币同时拿走。
可以根据状态进行DP,两种状态,当前第i个数和前一个数组合,或不要当前的数,使其和后面的数一起拿走,这样两两取走,将得到最优价值。

存在两种状态 dp1[i]=dp2[i-1]+a[i]+a[i-1] 表示取当前硬币和第i-k枚硬币,并且这个dp是求累加和的过程。
第二种情况,dp2[i]=max(dp1[i-k],dp2[i-k]) 表示不取当前第i枚硬币,将其放到i+k枚硬币的时候考虑,那么此处的dp值则继承自i-k处选择的最大值,从而延续得到最优解。

最终递推到底,取最后n-k+1项求和累加,表示有k个被两两取走的最优序列求和。

另有一种解法,对每个序号的值,%T取余,得到的值将表示该序号属于哪个序列的值,将其放入vector中存储,最后形成T个vector,每个vector中的值将是一个最优序列包括的所有序号。因为是两两取走,如果有vector中存在值是奇数,则去掉一个。最后求和而得到所有序列的最大价值

代码如下:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define LL long long
using namespace std;
LL a[100005],dp1[100005],dp2[100005];
int main()
{
    int n,k;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        memset(dp1,0,sizeof(dp1));
        memset(dp2,0,sizeof(dp2));
        for(int i=1; i<=n; i++)scanf("%d",&a[i]);
        for(int i=k+1; i<=n; i++)///从k+1位开始推,这样方便对i和i-k位求和
        {
            dp1[i]=dp2[i-k]+a[i]+a[i-k];///dp1表示 取  i-2k及i-3k的和 以及i到i-k的和作为待选值
            dp2[i]=max(dp1[i-k],dp2[i-k]);///dp2表示,在i位时,选i-k及i-2k 的和  与   i-k的最大值  比较取较大值
        }
        LL ans=0;
        for(int i=n-k+1; i<=n; i++)ans+=max(dp1[i],dp2[i]);///最后取最后k位总和求和,也就是k串序列,k次抽取个总和
        printf("%lld
",ans);
    }
}
原文地址:https://www.cnblogs.com/kuronekonano/p/11135855.html