《演算法競賽進階指南》0x55環形及後效性處理DP 休息時間
阿新 • • 發佈:2020-07-31
題目連結:http://poj.org/problem?id=2228
一個DP問題:一天24小時連續,0——1為第1小時,每天有n個小時,每個小時都有一個睡眠收益,問睡m個小時最多獲得的收益是多少。
由於這是一個環狀的問題,每個時刻可能在睡覺也可能不在睡覺,為了去掉環狀結構,可以將決策分成第n個小時在睡覺和第n個小時不在睡覺,狀態F[i,j,0/1]表示從第1個小時開始,前i個小時睡了j小時,並且第i個小時在睡覺和第i個小時不在睡覺的最大收益。兩種決策不同的是初值,最終只要取F[n,m,0]或者F[n,m,1]即可。
由於記憶體64M的限制,所以陣列可以通過滾動進行優化。1e7的int所佔的空間大約是40M。
程式碼:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 4000; int w[maxn]; int f[2][maxn][2]; int n,m; int main(){ cin>>n>>m; for(int i=1;i<=n;i++)cin>>w[i]; //第N小時不在睡覺 memset(f,-0x3f,sizeof f); int ans=-1; f[1][0][0]=f[1][1][1]=0; for(int i=2;i<=n;i++){ for(int j=0;j<=m;j++){ f[i & 1][j][0]=max(f[i-1 & 1][j][0],f[i-1 & 1][j][1]); if(j)f[i & 1][j][1]=max(f[i-1 & 1][j-1][0],f[i-1 & 1][j-1][1]+w[i]); } } ans=max(ans,f[n & 1][m][0]); memset(f,-0x3f,sizeof f); f[1][0][0]=0; f[1][1][1]=w[1]; for(int i=2;i<=n;i++){ for(int j=0;j<=m;j++){ f[i & 1][j][0]=max(f[i-1 & 1][j][0],f[i-1 & 1][j][1]); if(j)f[i & 1][j][1]=max(f[i-1 & 1][j-1][0],f[i-1 & 1][j-1][1]+w[i]); } } ans=max(ans,f[n & 1][m][1]); cout<<ans<<endl; }