揹包問題
①01揹包每件物品最多使用一次
②完全揹包每件物品有無限個
③多重揹包每種物品最多有si個 (存在樸素版和優化版)
④分組揹包沒組最多只能選 1 個
dp優化:對dp方程進行等價變形
dp最重要的就是公式推導(對於當前狀態的計算)
要滿足兩個條件:①不重 ②不漏
最簡單的01揹包
d p[
i][j
]=ma
x(dp
[i−1
][j]
,dp[
i−1]
[j−v
[i]]
+w[i
])
;dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+w[i]);
dp[i][
j]=m
ax(d
p[i−
1][j
],dp
[i−1
][j−
v[i]
]+w[
i]);
當前的值等於加入第i個物品和不加入第i個數(保證體積總值小於v)的最大的值。
1.樸素版:
#include using namespace std;
const int maxn=1e3+5;
int v[maxn],w[maxn];
int dp[maxn][maxn];
int main()
for(int i=1;i<=n;i++)
} cout<2.空間(和時間)優化版
可以使用滾動陣列來優化(節約空間)
同時在第二遍迴圈的時候節約了時間
因為f(i)這層只用到了f(i-1)這一層。
#include using namespace std;
const int maxn = 1e3+5;
int v[maxn],w[maxn];
int dp[maxn];
int main()
for(int i=1;i<=n;i++)
} cout《每件物品可以放入無限次,求最大價值。
1.樸素版
狀態轉移公式
d p[
i][j
]=ma
x(dp
[i−1
][j]
,dp[
i−1]
[j−k
∗v[i
]]+k
∗w[i
])
;dp[i][j]=max(dp[i-1][j],dp[i-1][j-k*v[i]]+k*w[i]);
dp[i][
j]=m
ax(d
p[i−
1][j
],dp
[i−1
][j−
k∗v[
i]]+
k∗w[
i]);
相當於不選和選k個進行比較,找到最大的價值
#include using namespace std;
const int maxn = 1e3+5;
int v[maxn],w[maxn];
int dp[maxn][maxn];
int main()
} }cout<2.優化版
f [i
,j]=
f[i−
1,j−
v[i]
∗k]+
w[i]
∗k
f[i,j]=f[i-1,j-v[i]*k]+w[i]*k
f[i,j]
=f[i
−1,j
−v[i
]∗k]
+w[i
]∗kf [ i , j ] = max ( f [ i - 1 , j ] , f [ i - 1 , j - v ] + w , f [ i - 2 , j - 2 * v ] + 2 * w… )
f [ i , j - v ] = max ( f [ i -1 , j - v ] , f [ i - 2 , j - v * 2] + w … )
f [ i , j ] = max( f [ i - 1 , j ] , f [ i , j - v ] + w ) //表示當滿足可以放第i個物品的時候判斷是否價值會更大。
//普通優化
#include using namespace std;
const int n = 1e3+4;
int v[n],w[n];
int dp[n][n];
int main()
} coutconst int n = 1e3+4;
int v[n],w[n];
int dp[n];
int main()
} cout《每件物品最多能放入si次,求最大價值。
1.樸素版
時間複雜度o(n v s)
#include using namespace std;
const int n = 1e3+4;
int v[n],w[n],s[n];
int dp[n][n];
int main()
} }cout<2.優化為01揹包版
二進位制優化方式
將si個物品打包好後簡化成01揹包問題。
例:1023
1 2 4 8 ,,,512 進行01揹包可以湊出1-1023中任意的數。
1 ->0 1
1 2 -> 0 1 2 3
1 2 3 -> 0 1 2 3 4 5 6
1…512 -> 0-1023
這樣就把應該列舉的1024次簡化為了10次。
1 2 4 8 16 32 64 73(200-127)
8次可以簡化200次 lg 200
優化後的時間複雜度o(n v lg s)
#include using namespace std;
const int n = 250005,m=2010;
int v[n],w[n],dp[n],cnt;
int main()
if(s>0)
} n=cnt;
for(int i=1;i<=n;i++)
} cout<4.分組揹包
如果是從當前這層數組更新,那麼從前往後遍歷。
每組要一種,求最大價值
直接上滾動陣列版
#include #include using namespace std;
const int n = 110;
int n,m;
int v[n][n],w[n][n],s[n];
int f[n];
int main()
} for(int i=1;i<=n;i++)
}} }
cout
}
學習筆記 動態規劃 I 初識DP
更新日期 2018 3 16,2018 12 03 動態規劃,簡稱dp dynamic programming 簡介1簡介2 動態規劃十分奇妙,它可以變身為記憶化搜尋,變身為遞推,甚至有時可以簡化成乙個小小的算式。動態規劃十分靈活,例如 noip2018 pj t3 擺渡車 寫法有很多很多,但時間 ...
動態規劃 dp
威威貓系列故事 打地鼠 威威貓最近不務正業,每天沉迷於遊戲 打地鼠 每當朋友們勸他別太著迷遊戲,應該好好工作的時候,他總是說,我是威威貓,貓打老鼠就是我的工作!無話可說.我們知道,打地鼠是一款經典小遊戲,規則很簡單 每隔乙個時間段就會從地下冒出乙隻或多隻地鼠,玩遊戲的人要做的就是打地鼠。假設 1 每...
動態規劃,dp
線性動規區間動規樹形動規 區間動規 根據題目要求,全域性最優滿足區域性最優 典型題例 加分二叉樹 洛谷1040 題目介紹 題目描述 設乙個n 個節點的二叉樹t 的中序遍歷為 1,2,3,n 其中數字 1,2,3,n 為節點編號。每個節點都有乙個分數 均為正整數 記第j 個節點的分數為dj。二叉樹t ...