POJ 2228 Naptime

来源:互联网 发布:阿里云服务器网站备案 编辑:程序博客网 时间:2024/06/05 21:17

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个小时)。

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

输入

  • 第一行为两个数,NB
  • 下面为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]));}
原创粉丝点击