pku2228_Naptime

来源:互联网 发布:java在线鲜花销售系统 编辑:程序博客网 时间:2024/06/02 06:14
http://poj.org/problem?id=2228


先考虑如何暴力:
每一段,有睡和不睡两种选择。任意一个长度为N且恰好包含B个1的01串正好对应了一组解。所以解空间是O(2^n)。


然后考虑如何优化:
f[i][j][flag]:表示长度为i,恰好有j个1,且第i个为flag(flag的取值为{0,1},表示没睡和有睡)
然后f[i][j][flag]能从f[i-1][j][flag](第i段不睡)和f[i-1][j-1][flag](第i段睡)推出来,所以转移是O(1)。
转移方程:f[i][j][0] = max(f[i-1][j][0], f[i-1][j][1])
        f[i][j][1] = max(f[i-1][j-1][0], f[i-1][j-1][1] + utility[i])


接着考虑circle的问题:
分三种情况讨论:
(1)第一段不睡,这样最后一段睡不睡都无所谓:
边界为:f[1][0][0] = 0, f[1][1][1] = -INF
结果为:max(f[n][b][0], f[n][b][1])
(2)第一段睡,最后一段也睡:
边界为:f[1][1][1] = utility[1], f[1][0][0] = -INF
结果为:f[n][b][1]
(3)第一段睡,最后一段不睡:
边界为:f[1][1][1] = 0, f[1][0][0] = -INF
结果为:f[n][b][0]

【注意】之所以没有在后面贴多一截,然后直接dp,是因为这样做,状态不好表示:f[i][j][flag]表示的i个位不知道是从哪里到哪里的i个位,如果按照这样的做法,那么复杂度会变高。


最后考虑初始化的问题:
1、不能全部都memset为-INF:因为f[i][0][0]都被置为-INF,即意味着前i段都不睡是不可能的。
2、不能全部都memset为0:因为像f[i][0][1]这样的状态是不可能发生的,所以必须置为-INF。
3、解决方法:先全部置为-INF,然后在每次循环前把f[i][0][0]置为0。


要注意的问题:
由于N的范围是[3, 3830],B的范围是[2, N),这样数组至少是3830*3830*2,果断MLE,超内存了。
鉴于第i段只与第i-1段有关,所以果断用滚动数组,这样就变成了2*3830*2,明显降了一个阶了。




代码:

#include <cstdio>#include <cstring>#include <algorithm>#include <fstream>using namespace std;const int NEGINF = -999999999;const int N = 3830 + 10;int f[2][N][2];int u[N];int n, b;void solve(){    for (int i = 2; i <= n; i++)    {        f[i%2][0][0] = 0;        for (int j = 1; j <= b; j++)        {            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] + u[i], f[(i-1)%2][j-1][0]);        }    }}int main(){    //freopen("a", "r", stdin);    //freopen("b", "w", stdout);    while (scanf("%d%d", &n, &b) != EOF)    {        for (int i = 1; i <= n; i++)            scanf("%d", &u[i]);        //1 awake        memset(f, 200, sizeof(f));        f[1][0][0] = 0, f[1][1][1] = NEGINF;        solve();        int tmp1 = max(f[n%2][b][0], f[n%2][b][1]);        //1 sleep, n sleep        memset(f, 200, sizeof(f));        f[1][0][0] = NEGINF, f[1][1][1] = u[1];        solve();        int tmp2 = f[n%2][b][1];        //1 sleep, n awake        memset(f, 200, sizeof(f));        f[1][0][0] = NEGINF, f[1][1][1] = 0;        solve();        int tmp3 = f[n%2][b][0];        printf("%d\n", max(max(tmp1, tmp2), tmp3));    }}


原创粉丝点击