poj2228 Naptime【(环结构)线性DP】

Naptime
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions:3374   Accepted: 1281

Description

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?

Input

* 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

Output

The day is divided into 5 periods, with utilities 2, 0, 3, 1, 4 in that order. Goneril must pick 3 periods.

Sample Input

5 3
2
0
3
1
4

Sample Output

6

Hint

INPUT DETAILS: 

The day is divided into 5 periods, with utilities 2, 0, 3, 1, 4 in that order. Goneril must pick 3 periods. 

OUTPUT DETAILS: 

Goneril can get total utility 6 by being in bed during periods 4, 5, and 1, with utilities 0 [getting to sleep], 4, and 2 respectively.

Source

 

题意:

一天有n个时间,有一只牛希望一天可以休息睡小时。如果牛在第i时刻已经熟睡,他可以得到ui的休息。但是如果他在i时刚刚入睡,他不能得到休息。牛可以从前一天晚上睡到第二天。睡觉时间也不一定连续。问如何安排睡觉时间,可以使牛得到的休息最大。

 

思路:

如果牛休息的时间不能从前一天跨越到第二天的话,就是一道典型的线性DP

我们先假设不能跨越,那么第1个小时一定得不到休息。用dp[i][j][0]和dp[i][j][1]分别表示,在第i时刻休息了j小时并且第i时刻在睡觉,和在第i时刻休息了j小时并且第i时刻不在睡觉的最大休息值。跑一遍DP,在dp[n][b][0], dp[n][b][1]中选择最优解。

这种假设的情况下,我们可以发现和题意原来的意思就差了第1个小时的时候。那么我们强制令第n个时刻和第1个时刻都在睡觉,也就是说第1个时刻可以得到休息值。再跑一遍DP,把dp[n][b][1]和之前的最优解比较取最优就是答案

本题的解法本质上是把问题拆成了两部分。这两部分合起来可以覆盖整个问题。无论是哪一部分,因为第n小时和第1小时之间的特殊关系被确定,我们就可以把环拆开,用线性DP计算。

 

注意点:

最开始开的数组是dp[maxn][maxn][2], MLE了。对于这种i由i-1推出的dp,第一维只需要2就够了。使用滚动数组,把原来是i的地方都变为i&1。

还需要注意状态转移时需要判断j是否大于1

 

虐狗宝典笔记:

对于环形结构的DP,有两种解决策略。

1.执行两次DP,第一次在任意位置把环断开成链,按照线性问题求解。第二次通过适当的条件和赋值,保证计算出的状态等价于把断开的位置强制相连。

2.在任意位置把环断开成链,然后复制一倍接在末尾。

复制代码
 1 //#include <bits/stdc++.h>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<stdio.h>
 6 #include<cstring>
 7 #include<vector>
 8 #include<map>
 9 
10 #define inf 0x3f3f3f3f
11 using namespace std;
12 typedef long long LL;
13 
14 int n,b;
15 const int maxn = 3835;
16 int u[maxn], dp[2][maxn][2];
17 
18 int main()
19 {
20     while(scanf("%d%d", &n, &b) != EOF){
21         for(int i = 1; i <= n; i++){
22             scanf("%d", &u[i]);
23         }
24         if(b == 0){
25             printf("0\n");
26             continue;
27         }
28 
29         memset(dp, -inf, sizeof(dp));
30         dp[1][0][0] = 0;dp[1][1][1] = 0;
31         for(int i = 2; i <= n; i++){
32             for(int j = 0; j <= i; j++){
33                 dp[i & 1][j][0] = max(dp[(i - 1) & 1][j][0], dp[(i - 1) & 1][j][1]);
34                 if(j >= 1)dp[i & 1][j][1] = max(dp[(i - 1) & 1][j - 1][0], dp[(i - 1) & 1][j - 1][1] + u[i]);
35             }
36         }
37         int ans = max(dp[n & 1][b][0], dp[n & 1][b][1]);
38 
39         memset(dp, -inf, sizeof(dp));
40         dp[1][1][1] = u[1];
41         for(int i = 2; i <= n; i++){
42             for(int j = 0; j <= i; j++){
43                 dp[i & 1][j][0] = max(dp[(i - 1) & 1][j][0], dp[(i - 1) & 1][j][1]);
44                 if(j >= 1)dp[i & 1][j][1] = max(dp[(i - 1) & 1][j - 1][0], dp[(i - 1) & 1][j - 1][1] + u[i]);
45             }
46         }
47         ans = max(ans, dp[n & 1][b][1]);
48 
49         printf("%d\n", ans);
50     }
51     return 0;
52 }
复制代码

 

posted @   wyboooo  阅读(1457)  评论(0编辑  收藏  举报
编辑推荐:
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
阅读排行:
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· 趁着过年的时候手搓了一个低代码框架
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!
点击右上角即可分享
微信分享提示