【bzoj1737】[Usaco2005 jan]Naptime 午睡时间 dp

题目描述

Goneril is a very sleep-deprived cow. Her day is partitioned into N (3 <= N <= 3,830) equal time periods but she can spend only B (2 <= B < N) not necessarily contiguous periods in bed. Due to her bovine hormone levels, each period has its own utility U_i (0 <= U_i <= 200,000), which is the amount of rest derived from sleeping during that period. These utility values are fixed and are independent of what Goneril chooses to do, including when she decides to be in bed. With the help of her alarm clock, she can choose exactly which periods to spend in bed and which periods to spend doing more critical items such as writing papers or watching baseball. However, she can only get in or out of bed on the boundaries of a period. She wants to choose her sleeping periods to maximize the sum of the utilities over the periods during which she is in bed. Unfortunately, every time she climbs in bed, she has to spend the first period falling asleep and gets no sleep utility from that period. The periods wrap around in a circle; if Goneril spends both periods N and 1 in bed, then she does get sleep utility out of period 1. What is the maximum total sleep utility Goneril can achieve?

贝茜是一只非常缺觉的奶牛.她的一天被平均分割成N段(3≤N≤3830),但是她要用其中的B段时间(2≤B< N)睡觉.每段时间都有一个效用值Ui(0≤Ui≤200000),只有当她睡觉的时候,才会发挥效用.    有了闹钟的帮助,贝茜可以选择任意的时间入睡,当然,她只能在时间划分的边界处入睡、醒来.    贝茜想使所有睡觉效用的总和最大.不幸的是,每一段睡眠的第一个时间阶段都是“入睡”阶段,而旦不记入效用值.    时间阶段是不断循环的圆(一天一天是循环的嘛),假如贝茜在时间N和时间1睡觉,那么她将得到时间1的效用值.

输入

* Line 1: Two space-separated integers: N and B

* Lines 2..N+1: Line i+1 contains a single integer, U_i, between 0 and 200,000 inclusive

    第1行:两个整数,N和B.
    第2到N+1行:每行1个数字,代表了时间i的效用值.

输出

* Line 1: A single integer, the maximum total sleep utility Goneril can achieve.

    最大的效用值.

样例输入

5 3
2
0
3
1
4

样例输出

6


题解

dp

先不管环的问题,想象成一个时间段。

那么很容易想到状态转移方程:

f[i][j]=max(f[i-1][j-1]+w[i],g[i-1][j-1])

g[i][j]=max(f[i-1][j],g[i-1][j])

其中f[i][j]表示前i个小时中总共睡j个小时,且其i个小时睡的最大效用值,

    g[i][j]表示前i个小时中总共睡j个小时,且其i个小时不睡的最大效用值。

答案就是max(f[n][b],g[n][b])。

然后考虑环的问题。

除了刚才讨论的情况之外,如果出现环,一定是从某个点开始,经过n和1,再停止。

这时候n和1一定是睡的情况。

考虑断环,那么和正常情况相比,唯一的区别就是从1开始的一段中,w[1]也算进了答案中(题目中描述:每一段的第一段都不算进效用值)。

所以改一下初始条件,再按照同样的方法跑一遍dp即可,答案是f[n][b]。

最后取最大值即可。

由于空间限制,需要使用滚动数组黑科技,看代码应该不难理解。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int f[2][3831] , g[2][3831] , w[3831];
int main()
{
    int n , b , i , j , ans = 0x80808080;
    scanf("%d%d" , &n , &b);
    for(i = 1 ; i <= n ; i ++ )
        scanf("%d" , &w[i]);
    memset(f , 0x80 , sizeof(f));
    memset(g , 0x80 , sizeof(g));
    f[1][1] = g[1][0] = 0;
    for(i = 2 ; i <= n ; i ++ )
    {
        for(j = 0 ; j <= b ; j ++ )
        {
            if(j)
                f[i & 1][j] = max(f[(i & 1) ^ 1][j - 1] + w[i] , g[(i & 1) ^ 1][j - 1]);
            g[i & 1][j] = max(f[(i & 1) ^ 1][j] , g[(i & 1) ^ 1][j]);
        }
    }
    ans = max(f[n & 1][b] , g[n & 1][b]);
    memset(f , 0x80 , sizeof(f));
    memset(g , 0x80 , sizeof(g));
    f[1][1] = w[1];
    for(i = 2 ; i <= n ; i ++ )
    {
        for(j = 0 ; j <= b ; j ++ )
        {
            if(j)
                f[i & 1][j] = max(f[(i & 1) ^ 1][j - 1] + w[i] , g[(i & 1) ^ 1][j - 1]);
            g[i & 1][j] = max(f[(i & 1) ^ 1][j] , g[(i & 1) ^ 1][j]);
        }
    }
    ans = max(ans , f[n & 1][b]);
    printf("%d
" , ans);
    return 0;
}
原文地址:https://www.cnblogs.com/GXZlegend/p/6393349.html