POJ 2228 Naptime

POJ 2228 原题

题目描述

在某个星球上,一天由 N 个小时构成,我们称0点到 1 点为第1个小时、 1 点到2点为第 2 个小时,以此类推。在第i个小时睡觉能够恢复 Ui 点体力。在这个星球上住着一头牛,它每天要休息 B 个小时。它休息的这B个小时不一定连续,可以分成若干段,但是在每段的第一个小时,它需要从清醒逐渐入睡,不能恢复体力,从下一个小时开始才能睡着。

为了身体健康,这头牛希望遵循生物钟,每天采用相同的睡觉计划。另外,由于时间是连续的,即每一天的第 N 个小时和下一天的第1个小时是相连的( N 点等于0点),这头牛只需要在每 N 个小时内休息够B个小时就可以了(就像地球上的人类,如果每天需要休息 9 个小时,那么可以23点入睡、 6 点起床,13点再午睡、 15 点起床,这样能够恢复体力的时间就是从 06 点和 1415 点,共 7 个小时)。

请你帮忙给这头牛安排一个睡觉计划,使它每天恢复的体力最多。

输入

  • 第一行为两个数,N B
  • 下面为N+1行,每行包含一个数字: Ui

    0Ui200000,2B<N,3N3830

    输出

    • 可恢复的最大能量值。

    样例输入

    5 3
    2
    0
    3
    1
    4

    样例输出

    6

    提示

    牛在第 4 小时开始入睡,未睡着。
    在第56小时已经入睡,得到 2+4=6 的能量。

    Sol

    Easy Ver.

    先来考虑一下简化的问题:第 N 个小时和下一天的第一个小时不是连着的。
    f[i][j][1]表示前i个小时共休息了j小时,现在正在休息,累计恢复的体力的最大值。
    f[i][j][1]表示前 i 个小时共休息了j小时,现在不在休息,累计恢复的体力的最大值。
    注意:i包括现在。
    可知:

    f[i,j,0]=max(f[i1,j,0],f[i1,j,1])f[i,j,1]=max(f[i1,j1,0],f[i1,j1,1]+U[i])

    1. f[i1,j,0] 为现在不休息,且上个小时也不休息。
    2. f[i1,j,1] 为现在不休息,上个小时休息了。
    3. f[i1,j1,0] 为现在休息,上个小时没休息(刚休息不加能量)。
    4. f[i1,j1,1]+U[i] 为现在休息,上个小时已经休息了(加能量)。
    这时的答案应该是:

    ans=max(f[N.B,1],f[N,B,0])

    除了 f[1,0,0]=0 外,其他的全设为

    Original Mode

    这个简化的问题与原问题的差别:
    可能漏掉了第 N 个小时和第1个小时休息恢复的体力。
    可以考虑一下2种情况:
    1. 1时休息,N时不休。
    2. 1时休息,N时也休。

    综上所述(边界条件)
    • (1)第一段不睡,这样最后一段睡不睡都无所谓:
      边界为:f[1][0][0] = 0, f[1][1][1] = -INF
      f[1,0,0]1f[1,1,1]
      结果为:max(f[N][B][0], f[N][B][1])
    • (2)第一段睡,最后一段也睡:
      边界为:f[1][1][1] = utility[1], f[1][0][0] = -INF
      f[1,1,1]1f[1,0,0]1
      结果为:f[N][B][1]
    • (3)第一段睡,最后一段不睡:
      边界为:f[1][1][1] = 0, f[1][0][0] = -INF
      f[1,1,1]1f[1,0,0]1
      结果为:f[N][B][0]

    初始化的问题

    1. 不能全部把F[][][]都设定为-INF:因为f[i][0][0]都被置为-INF,即意味着“前i小时都不睡是不可能发生的”,然而是可以最后几个小时休息的。
    2. 不能全部把F[][][]都设定为0:因为像f[i][0][1]这样的状态(共睡了0小时,现在正在休息)是不可能发生的,所以必须置为-INF
    3. 解决方法:先全部置为-INF,设定边界条件,然后在每次循环前把f[i][0][0]置为0。

    要注意的问题

    由于N的范围是 N[3,3830] ,B的范围是 B[2,N) ,这样数组至少是 383038302 ,空间复杂度过高。
    鉴于第 i 段只与第i1段有关,所以果断用滚动数组,这样就变成了2*3830*2,明显下降不少了。

    代码

    #include <cstdio>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    
    #define __INITIALIZE memset(f, 0xc0c0c0c0, sizeof f)
    #define rep(i, j, k) for (int i = j; i <= k; i++)
    
    using namespace std;
    
    inline int read() {
        int r = 0;
        char cc = getchar();
        while (!isdigit(cc)) cc = getchar();
        while (isdigit(cc)) {
            r = r * 10 + cc - 48;
            cc = getchar();
        }
        return r;
    }
    
    int n, b;
    int f[2][3831][2];
    int r[3831];
    int temp[3];
    
    void solve() {
        rep (i, 2, n) {
            f[i % 2][0][0] = 0;
            rep (j, 1, b) {
                f[i % 2][j][0] = max(f[(i - 1) % 2][j][0], f[(i - 1) % 2][j][1]);
                f[i % 2][j][1] = max(f[(i - 1) % 2][j - 1][1] + r[i], f[(i - 1) % 2][j - 1][0]);
            }
        }
    }
    
    int main(int argc, char **argv) {
        n = read();
        b = read();
        for (int i = 1; i <= n; i++) {
            r[i] = read();
        }
    
        //1 awake
        __INITIALIZE;
        f[1][0][0] = 0;
        f[1][1][1] = 0xc0c0c0c0;
        solve();
        temp[0] = max(f[n % 2][b][1], f[n % 2][b][0]);
    
        //1 sleep, n awake
        __INITIALIZE;
        f[1][0][0] = 0;
        f[1][1][1] = 0;
        solve();
        temp[1] = f[n % 2][b][0];
    
        //1 sleep, n sleep
        __INITIALIZE;
        f[1][1][1] = r[1];
        f[1][0][0] = 0xc0c0c0c0;
        solve();
        temp[2] = f[n % 2][b][1];
    
        printf("%d", max(max(temp[0], temp[1]), temp[2]));
    }
阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hydroge

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值