原題連接html
題目特殊在:每一天的第 N N N小時和下一天的第 1 1 1小時是相連的, 即一個環形
咱們假設每一天的第 N N N小時和下一天的第 1 1 1小時不相連,則題目就變成了一個線性DP問題
很容易設計出狀態
:
f [ i , j , 0 ] f[i,j,0] f[i,j,0]表示只考慮只考慮前 i i i個小時,一共休息了 j j j個小時, 而且第 i i i個小時沒休息的全部方案的最大收益
f [ i , j , 1 ] f[i,j,1] f[i,j,1]表示只考慮前 i i i個小時,一共休息了 j j j個小時, 而且第 i i i個小時在休息的全部方案的最大收益
獲得狀態轉移方程:
f [ i , j , 0 ] = m a x ( 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,0]=max(f[i−1,j,0],f[i−1,j,1])
f [ i , j , 1 ] = m a x ( f [ i − 1 , j − 1 , 0 ] , f [ i − 1 , j − 1 , 1 ] + w [ i ] ) f[i,j,1] = max(f[i-1,j-1,0],f[i-1,j-1,1]+ w[i]) f[i,j,1]=max(f[i−1,j−1,0],f[i−1,j−1,1]+w[i])
( w [ i ] w[i] w[i]爲第 i i i小時熟睡得到的體力,題目規定每段的第 1 1 1個小時須要入睡,從而進入熟睡狀態,不能恢復體力)
初始化
: 由於因爲不相連, 因此第1小時必定不會是熟睡狀態
f [ 1 , 0 , 0 ] = 0 f[1,0,0] = 0 f[1,0,0]=0, f [ 1 , 1 , 1 ] = 0 f[1,1,1] = 0 f[1,1,1]=0, 其他狀態都是 − ∞ -\infty −∞
所求答案
即 m a x ( f [ N , B , 0 ] , f [ N , B , 1 ] ) max(f[N,B,0],f[N,B,1]) max(f[N,B,0],f[N,B,1])
如今咱們考慮每一天的第 N N N小時和下一天的第 1 1 1小時是相連的, 其實就比上述集合多 1 1 1種狀況
即: 第 1 1 1個小時是熟睡狀態, 要使第 1 1 1個小時是熟睡狀態, 須要強制第 N N N個小時休息
則只需更改初始條件
: f [ 1 , 1 , 1 ] = w [ 1 ] f[1,1,1] = w[1] f[1,1,1]=w[1],其他狀態都是 − ∞ -\infty −∞
所求答案
即 f [ N , B , 1 ] f[N,B,1] f[N,B,1]
回顧上述過程, 實際上咱們經過第 1 1 1小時是否處於熟睡狀態將全部狀態劃分紅兩類
這就是咱們要介紹的第一種策略——執行兩次DP,第一次在任意位置把環斷開成鏈,按照線性問題求解;第二次經過適當的條件和賦值,保證計算出的狀態等價於把斷開的位置強制相連(摘自算法競賽進階指南
)ios
滾動數組優化空間複雜度
注意到題目有 64 M B 64MB 64MB空間, 而數據範圍 N N N最大爲 3830 3830 3830, 若用數組 f [ N ] [ N ] [ 2 ] f[N][N][2] f[N][N][2]表示全部狀態, 大概是 120 M B 120MB 120MB( 3830 × 3830 × 2 ≈ 3 e 7 , 1 e 7 的 i n t 數 組 大 概 是 40 M B 3830×3830×2 ≈ 3e7,1e7的int數組大概是40MB 3830×3830×2≈3e7,1e7的int數組大概是40MB)明顯不夠用
注意到狀態轉移方程: 第 i i i層的狀態只與上一層 i − 1 i-1 i−1的狀態有關, 即可以用 i & 1 i\&1 i&1將第一維壓縮成 f [ 2 ] [ ] [ ] f[2][][] f[2][][]
f [ i , j , 0 ] = m a x ( 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,0]=max(f[i−1,j,0],f[i−1,j,1])
f [ i , j , 1 ] = m a x ( f [ i − 1 , j − 1 , 0 ] , f [ i − 1 , j − 1 , 1 ] + w [ i ] ) f[i,j,1] = max(f[i-1,j-1,0],f[i-1,j-1,1]+ w[i]) f[i,j,1]=max(f[i−1,j−1,0],f[i−1,j−1,1]+w[i])web
也能夠參考Y總視頻講解算法
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N = 3839; int f[2][N][2], w[N]; int n, b; int main() { cin >> n >> b; for(int i=1; i<=n; i++) cin >> w[i]; // 第1個小時不在熟睡狀態 memset(f,-0x3f, sizeof(f)); f[1&1][0][0] = f[1&1][1][1] = 0; for(int i=2; i<=n; i++) { for(int j=0; j<=min(i,b); 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]); // 保證j-1不越界 } } int ans = max(f[n&1][b][0], f[n&1][b][1]); // 第1個小時在熟睡狀態 memset(f,-0x3f, sizeof(f)); f[1&1][1][1] = w[1]; for(int i=2; i<=n; i++) { for(int j=0; j<=min(i,b); 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][b][1]); cout << ans << endl; return 0; }