【动态规划】【USACO18DEC】Teamwork

题目链接:

【小结】:

这个题,和我想的不太一样,我真的受到昨天的一个题影响了,一直没有想法,后来大家都说是dp,我才反应回来,不难想到就是dp,但是怎么写这个状态方程呢???这就让我很迷糊了。。。做题做得太少了,所以才写不出来。

【题意】:

这个题目挺有意思的,就是农夫John,然后他有n头牛,然后每一头牛都有各自的打包装的本领,然后农夫John分组(最多为k头牛一组)后可以让组内的所有牛  都获得组内牛中最高能力值,给你n,k,给出n个数,然后可以宁最多为k个连续的数为  该区域内的最大值,然后问,进行这个操作后怎么使得总和最大。

【题解】:

不难想到:dp[ N ],数组内,dp[i],表示以第i个为前缀的最大值,一直维护。是前缀而不是其他,因为如果是单个的最优不能保证全局的最优。    关键是:    然后怎么写出状态方程呢????

首先我们拿到的信息只有k,和k中区间内最大的。

苦死冥想之后,还是做不出来,最后赛后去看洛谷才发现简单的dp。

第一层for枚举1~n,第二层for枚举(写法有两种):

第一种可以是枚举后面的数   Max ( a[ j ] ) ,,使得在该位上变成 (j-i+1) *Max( a[ j ] )+dp[ i-1 ],一直维护最大值。

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+100;
int dp[N];
int main()
{
    int n,k,a[N];
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++){
        int maxz=0;
        for(int j=i;j<min(i+k,n+1);j++){
            maxz = max(maxz,a[j]);
            dp[j]= max(dp[j],dp[i-1]+(j-i+1)*maxz);
        }
    }
    printf("%d\n",dp[n]);
    return 0;
}

第二种可以枚举长度,但是这个方向是从枚举前面的数字,维护dp[i]的最值。

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+100;
int dp[N];
int main()
{
    int n,k,a[N];
    scanf("%d%d",&n,&k);
    for( int i=1;i<=n;i++ )scanf("%d",&a[i]);

    for(int i=1;i<=n;i++){
        dp[i]=dp[i-1]+a[i];
        int Maxz=a[i];
        for(int j=1;j<k;j++){ //注意j<k,而没有等于
            if(i-j>0){
                Maxz=max(Maxz,a[i-j]);
                dp[i]=max(dp[i],dp[i-j-1]+(j+1)*Maxz);
            }
        }
    }
    printf("%d\n",dp[n]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Z_sea/article/details/87295471
今日推荐