1. 程式人生 > 實用技巧 >《演算法競賽進階指南》0x55環形及後效性處理DP 休息時間

《演算法競賽進階指南》0x55環形及後效性處理DP 休息時間

題目連結: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; }