首先是01揹包(1):
【題目描述】有n個重量和價值分別是wi,vi的物品。從這些物品中挑選出總重量不超過W的物品,求所有挑選方案中價值總和的最大值。
限制條件:(PS限制條件不同,動態方程也不同)
1 <= n <= 100;
1 <= wi,vi <= 100;
1 <= W <= 10000;//此處W較大,而wi,vi較小
輸入
n = 4
(w,v)={(2,3),(1,2)(3,4),(2,2)}
W = 5
輸出
7(選擇第0,1,3號物品)
【分析一】
dp[i+1][j]:從0到i這i+1個物品中選出總重量不超過j的物品時總價值的最大值
dp[0][j]=0;
| dp[i][j] (j<w[i];
dp[i+1][j]= |
| max(dp[i][j], dp[i][j-w[i]+v[i]}) (其他)。
void solve(){
for(int i = 0; i < n; i++){
for(int j = 0; j <= W; j++){
if(j < w[i])
dp[i+1][j] = dp[i][j];
else
dp[i+1][j] = max(dp[i][j], dp[i][j-w[i]+v[i]]);
}
}
printf("%d\n", dp[n][W]);
}
【分析二】
void solve(){
for(int i = 0; i < n; i++){
for(int j = W; j >= w[i]; j--){//逆序
dp[j] = max(dp[j], dp[j- w[i]] + v[i]);
}
}
printf("%d\n", dp[W]);
}
01揹包(2):
還記得我們前面的條件嗎?在這裏,要把限制條件換一下
1 <= n <= 100
1 <= wi <= 10^7
1 <= vi <= 100
1 <= W <= 10^9
【分析】
dp[i+1][j]:=前i個物品中挑選出價值總和爲j時總質量的最小值(不存在時就是一個充分大的數值INF)
初始值
dp[0][0] = 0;
dp[0][j] = INF;
此外,前i個物品中挑選出機制總和爲j時,有
前i-1個物品中挑選價值總和爲j的部分
前i-1個物品中挑選價值總和爲j-v[i]的部分,然後再選中第i個物品
這兩種方法之一,所以就能得到
dp[i+1][j] = min(dp[i][j], dp[i][j-v[i] + w[i];
這一遞推式。最終的答案就在應以=於令dp[n][j] <= W的最大的j。
int dp[MAX_N+1][MAX_N * MAX_V + 1];//dp數組
void solve(){
fill(dp[0], dp[0] + MAX_N * MAX_V +1, INF);//此處需自己寫出代碼
dp[0][0] = 0;
for(int i = 0; i < n; i++){
for(int j = 0; j < MAX_N * MAX_V; j++){
if(j < v[i]){
dp[i+1][j] = dp[i][j];
}else{
dp[i+1][j] = min(dp[i][j], dp[i][j-v[i]] + w[i]);
}
}
}
int res = 0;
for(int i = 0; i <= MAX_N * MAX_V; i++)
if(dp[n][i] <= W)
res = i;
printf("%d\n", res);
}
完全揹包:
【題目描述】有n個重量和價值分別是wi,vi的物品。從這些物品中挑選出總重量不超過W的物品,求所有挑選方案中價值總和的最大值。在這裏,每種物品可以挑選任意多件。
限制條件:
1<=n<=100
1<=wi,vi<=100
1<=W<=10000
輸入
n = 3
(w, v) = {(3,4), (4,5), (2,3)}
W = 7
輸出
10(0號物品選1個,2號物品選2個)
【分析一】
令dp[i+1][j]:=從前i種物品中挑選總重不超過j時總價值的最大值。
dp[0][j]=0;
| max{dp[i-k*w[i]] + k*v[i] | 0<=k;}
dp[i+1][j] = |
| max{dp[i][j-k*w[i]] + k*v[i] | 0<=k;}
void solve(){
for(int i = 0; i < n; i++){
for(int j = 0; j <= W; j++){
for(int k = 0; k*w[i] <= j; k++){
dp[i+1][j] = max(dp[i+1][j], dp[i][j-k*w[i]] + k*v[i]);
}
}
}
printf("%d\n", dp[n][W]);
}
【分析二】
void solve(){
for(int i = 0; i < n; i++){
for(int j = w[i]; j <= W; j++){//順序
dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
}
}
printf("%d\n", dp[W]);
}