POJ 2228 Naptime 环形DP:执行两次DP

版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/88940422

title

POJ 2228
CH POJ2228
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

USACO 2005 January Gold

analysis

  • 先来考虑一个简化的问题。假设第 N N 个小时和下一天的第1个小时不是相连的,这样星球上每天的时间是线性的。
    我们就可以设 F [ i , j , 1 ] F[i,j,1] 表示前 i i 个小时休息了 j j 个小时,并且第 i i 个小时正在休息,累计恢复的体力的最大值。 F [ i , j , 0 ] F[i,j,0] 表示前 i i 个小时休息了 j j 个小时,并且第 i i 个小时没有在休息,累计恢复的体力的最大值。

    F [ i , j , 0 ] = max ( F [ i 1 , j , 0 ] , F [ i 1 , j , 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 ] + u [ i ] ) F[i,j,1]=\max(F[i-1,j-1,0],F[i-1,j-1,1]+u[i])
    初始条件: F [ 1 , 0 , 0 ] = 0 , F [ 1 , 1 , 1 ] = 0 F[1,0,0]=0,F[1,1,1]=0 其他均为负无穷。
    目标: max ( F [ N , B , 0 ] , F [ N , B , 1 ] ) \max(F[N,B,0],F[N,B,1])
  • 到目前为止,我们解决的“线性问题”仅仅比原来的“环形问题”少了一种情况,即在第1个小时熟睡,并获得 u [ 1 ] u[1] 点体力。为了补充这个缺少的情况,可以强制令第 N N 个小时和第1个小时都在休息,是第1个小时能够恢复体力。我们仍然采用上述线性DP的方式,只需要把初值和目标改一下:
    初始条件: F [ 1 , 1 , 1 ] = u [ 1 ] F[1,1,1]=u[1] 其他均为负无穷。
    目标: F [ N , B , 1 ] F[N,B,1]
  • 那么,两次DP中的最优解即为本题的答案。并且我们可以用按位与来进行滚动数组优化,减少空间复杂度。

code

#include<bits/stdc++.h>
using namespace std;
const int maxn=4100;
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1, ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}
int f[2][maxn][2];
int u[maxn],ans;
int main()
{
	int n,b;
	read(n);read(b);
	for (int i=1; i<=n; ++i)
		read(u[i]);
	memset(f,0xcf,sizeof(f));
	f[1][1][1]=f[1][0][0]=0;
	for (int i=2; i<=n; ++i)
		for (int j=0; j<=b; ++j)
		{
			f[i&1][j][0]=max(f[i-1&1][j][0],f[i-1&1][j][1]);
			if (j>=1) f[i&1][j][1]=max(f[i-1&1][j-1][0],f[i-1&1][j-1][1]+u[i]);
		}
	ans=max(ans,max(f[n&1][b][0],f[n&1][b][1]));
	memset(f,0xcf,sizeof(f));
	f[1][1][1]=u[1];
	for (int i=2; i<=n; ++i)
		for (int j=0; j<=b; ++j)
		{
			f[i&1][j][0]=max(f[i-1&1][j][0],f[i-1&1][j][1]);
			if (j>=1) f[i&1][j][1]=max(f[i-1&1][j-1][0],f[i-1&1][j-1][1]+u[i]);
		}
	printf("%d\n",max(ans,f[n&1][b][1]));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/88940422
今日推荐