01揹包:ide
n件物品,揹包最大載重爲W,第i件物品的重量爲w[i],價值爲v[i],求在不超過W的狀況下揹包內物品價值的最大總和。優化
狀態轉移方程:spa
f[j] = max(f[j], f[j - w[i]] + v[i])code
1≤i≤n, w[i]≤j≤Wblog
1 for(int i=1; i<=n; ++i) 2 for(int j=W; j>=w[i]; --j) 3 f[j] = max(f[j], f[j - w[i]] + v[i]);
徹底揹包:class
n種物品,每種物品能夠選無數次,循環
揹包最大載重爲W,第i種物品的重量爲w[i],價值爲v[i],求在不超過W的狀況下揹包內物品價值的最大總和。二進制
DP方程和01揹包的同樣,只不過循環順序要從逆序變成正序im
1 for(int i=1; i<=n; ++i) 2 for(int j=w[i]; j<=W; ++j) 3 f[j] = max(f[j], f[j - w[i]] + v[i]);
多重揹包:img
n種物品,每種物品有p[i]個,
揹包最大載重爲W,第i種物品的重量爲w[i],價值爲v[i],求在不超過W的狀況下揹包內物品價值的最大總和。
DP方程仍是和01揹包同樣,不過要在第二層加一個p[i]次的循環,表示這一件物品要選p[i]次
1 for(int i=1; i<=n; ++i) 2 for(int k=1; k<=p[i]; ++k) 3 for(int j=W; j>=w[i]; --j) 4 f[j] = max(f[j], f[j - w[i]] + v[i]);
多重揹包的二進制優化:
把k拆成1 + 2 + 4 + 8 + ... + 2n + x的形式,這樣原來的k件物品就變成了log2 k件,再作01揹包就好
1 int main() { 2 n = read(), W = read(); 3 int cnt = 0; 4 for(int i=1; i<=n; ++i) { 5 w[i] = read(), v[i] = read(), p[i] = read(); 6 int s = 1; 7 while(p[i] > s) { 8 ww[++cnt] = w[i] * s; 9 vv[cnt] = v[i] * s; 10 p[i] -= s; 11 s <<= 1; 12 } 13 if(p[i]) { 14 ww[++cnt] = w[i] * p[i]; 15 vv[cnt] = v[i] * p[i]; 16 } 17 } 18 for(int i=1; i<=cnt; ++i) 19 for(int j=W; j>=ww[i]; --j) 20 f[j] = max(f[j], f[j - ww[i]] + vv[i]); 21 }