參考
https://blog.csdn.net/qq_41925919/article/details/90267224
先不考慮環的情況
dp[i][j][0]:前i個時間間隔中,已經花費了j個間隔,取得的最大值,並且第i個間隔在休息
dp[i][j][1]:前i個時間間隔中,已經花費了j個間隔,取得的最大值,並且第i個間隔不休息
轉態轉移
dp[i&1][j][1] = max(dp[(i+1)&1][j][0],dp[(i+1)&1][j][1]);
dp[i&1][j][0] = max(dp[(i+1)&1][j-1][0] + a[i],dp[(i+1)&1][j-1][1]);
最後的結果 ans = max(dp[N][B][0],dp[N][B][1])
考慮成環
由於N值過大,將輸入變成兩倍接到後面的做法不可取,tle
我們先令dp[1][1][0] = a[1],即在上一天最後一個時間段一定在sleep
然後重新運行DP,這樣除了最後一段時間和第一段時間,其他的時間段都是成環之後的正確值。
我們再來看第一段和最後一段
在最後一段sleep的情況下,第一段顯然是正確的
這是我們取 ans = max(ans,dp[N][B][0]),即最後一段時間一定在睡覺即可。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <limits.h>
using namespace std;
#define debug(x) cout<<#x<<": "<<x<<endl;
int N,B;
int a[3831];
int dp[2][3031][2];
void disp(){
for(int i=0;i<=N;i++){
for(int j=0;j<=B;j++){
cout<<dp[i][j][0]<<" ";
cout<<dp[i][j][1]<<" ";
cout<<" ";
}
cout<<endl;
}
}
int main()
{
while( scanf("%d%d",&N,&B)!=EOF ){
memset(dp,0x80,sizeof(dp));
int ret = -1;
for(int i=1;i <= N;i++){
scanf("%d",&a[i]);
}
dp[1][0][1] = 0;
dp[1][1][0] = 0;
for( int i = 2;i <= N;i ++ ){
for(int j = 0;j <= B;j ++){
dp[i&1][j][1] = max(dp[(i+1)&1][j][0],dp[(i+1)&1][j][1]);
if(j){
dp[i&1][j][0] = max(dp[(i+1)&1][j-1][0] + a[i],dp[(i+1)&1][j-1][1]);
}
}
}
//debug(111)
ret = max(dp[N&1][B][0],dp[N&1][B][1]);
memset(dp,0x80,sizeof(dp));
dp[1][1][0] = a[1];
for(int i=2;i<=N;i++){
for(int j=0;j<=B;j++){
dp[i&1][j][1] = max(dp[(i+1)&1][j][0],dp[(i+1)&1][j][1]);
if(j){
dp[i&1][j][0] = max(dp[(i+1)&1][j-1][0]+a[i],dp[(i+1)&1][j-1][1]);
}
}
}
//disp();
//ret = max(ret,dp[N&1][B][1]);
ret = max(ret,dp[N&1][B][0]);
cout<<ret<<endl;
}
return 0;
}