有n件物品和乙個容量為v 的揹包。放入第i件物品耗費的空間是ci,得到 的價值是wi。
求解將哪些物品裝入揹包可使價值總和最大。
這是最基礎的揹包問題,特點是:每種物品僅有一件,可以選擇放或不 放。
用子問題定義狀態:即f[i, v]表示前i件物品恰放入乙個容量為v的揹包可以 獲得的最大價值。
則其狀態轉移方程便是:
對於「將前i件物品放入容量為v的揹包 2 中」這個子問題,若只考慮第i件物品的策略(放或不放),
那麼就可以轉化 為乙個只和前i − 1件物品相關的問題。
如果不放第i件物品,那麼問題就轉化 為「前i − 1件物品放入容量為v的揹包中」,價值為f[i − 1, v];
如果放第i件物 品,那麼問題就轉化為「前i − 1件物品放入剩下的容量為v − ci的揹包中」,
此時能獲得的最大價值就是f[i − 1, v − ci ]再加上通過放入第i件物品獲得的價 值wi。
#include#includeusing namespace std;
const int maxn = 105;
int dp[maxn][maxn];
int c[maxn];//第i件物品耗費的空間是ci
int w[maxn];//得到的價值是wi。
int main()
for(int i = 1;i <= n; i++)
//動態規劃邊界問題
for(int i = 0;i <= n; i++)
for(int i = 1;i <= n; i++)else}}
printf("%d\n",dp[n][v]);
} return 0;
}
以上方法的時間和空間複雜度均為o(v*n),其中時間複雜已經不能再優化,但是空間複雜度可以優化到o(n)。
先考慮上面講的基本思路是如何實現的,肯定是有乙個主迴圈 i = 1....n,每次算出來二維陣列f[i][0....v]的所有值;
如果只用乙個陣列f[0...v],能不能保證第i次迴圈結束後 f[v]中表示的就是我們定義的狀態 f[i][v]呢?
f[i][v]是由f[i-1][v]和f[i-1][v-c[i]]兩個子問題遞推出來,能否保證在推f[i][[v]時(即在第i次主迴圈中推f[v]時)能夠得到f[i-1][v]和
f[i-1][v-c[i]]的值呢?事實上,這要求在每次迴圈中我們以v=v......0的順序推 f[v],這樣才能保證推 f[v]時,f[v-c[i]]儲存的是狀態 f[i-1][v-c[i]] 的值。
#include#include#includeusing namespace std;
const int maxn = 105;
int dp[maxn];
int c[maxn];//第i件物品耗費的空間是ci
int w[maxn];//得到的價值是wi。
int main()
for(int i = 0;i < n; i++)
//動態規劃邊界問題
memset(dp,0,sizeof(dp));
for(int i = 0;i < n; i++)
}printf("%d\n",dp[v]);
} return 0;
}
求最優解的揹包問題中,有兩種問法:
1.求恰好裝滿揹包時的最優解。
初始化時,f[0]=0,f[1...v]為-inf(inf=0x3f3f3f3f),這樣最終得到的f[n]是一種恰好裝滿揹包的最優解
2.沒有要求必須把揹包裝滿,而是只希望**盡量大,初始化時應該將f[0..v]全部設 為0。
初始化的f陣列事實上就是在沒有任何物品可以放入揹包時的合 法狀態。
如果要求揹包恰好裝滿,那麼此時只有容量為0的揹包,可能的價值為0,只能被nothing「恰好 裝滿」,其它容量的揹包均沒有合法的解,屬於未定義的狀態,它們的值就都應該是−∞了。
如果 揹包並非必須被裝滿,那麼任何容量的揹包都有乙個合法解「什麼都不裝」,這個解的價值為0, 所以初始時狀態的值也就全部為0了。
有n種物品和乙個容量為v的揹包,每種物品都有無限件可用。第i種物品的費用是c[i], 價值是w[i]。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最 大。
這個問題非常類似於01揹包問題,所不同的是每種物品有無限件。也就是從每種 物品的角度考慮,與它相關的策略已並非取或不取兩種,而是有取0件、取1件、取2件……等很 多種。如果仍然按照解01揹包時的思路,令f[i][v]表示前i種物品恰放入乙個容量為v的揹包的最 大權值。仍然可以按照每種物品不同的策略寫出狀態轉移方程:
這跟01揹包問題一樣有o(vn)個狀態需要求解,但求解每個狀態的時間已經不是常數了,求解 狀態f[i][v]的時間是θ( v / c[i]),總的複雜度可以認為是θ(v ×∑ v / c[i]),是比較大的。
#include#includeusing namespace std;
const int maxn = 1005;
int dp[maxn][maxn];
int c[maxn],w[maxn];
int main()
for(int i = 1;i <= n; i++)
for(int i = 1;i <= n; i++)
for(int i = 1;i <= n; i++)}}
printf("%d\n",dp[n][v]);
} return 0;
}
完全揹包問題有乙個很簡單有效的優化:若兩件物品i、 j滿 足c[i] <= c[j]且w[i] >= w[j],則將物品j去掉,不用考慮。這個優化的正確性顯然:任何情況下都可 將價值小費用高得j換成物美價廉的i,得到至少不會更差的方案。對於隨機生成的資料,這個方 法往往會大大減少物品的件數,從而加快速度。然而這個並不能改善最壞情況的複雜度,因為 有可能特別設計的資料可以一件物品也去不掉。
首先將費用大於v的物品去掉,然後使用類似計數排序的做法,計算出費用相同 的物品中價值最高的是哪個,可以θ(v + n)地完成這個優化。
//完全揹包
#includeusing namespace std;
const int maxn=1e4+10;
int n;//n種物品
int v;//揹包容量
int c[maxn];
int w[maxn];
int dp[maxn];
int main()
} //動態規劃邊界問題
for(int i = 0;i <= n; i++)
for(int i = 1;i <= p; i++)else}}
printf("%d\n",dp[p-1][v]);
} return 0;
}
但是我們期望將它轉化為01揹包問題之後,能夠像完全揹包一樣降低複雜 度。 仍然考慮二進位制的思想,我們考慮把第i種物品換成若干件物品,使得原問 題中第i種物品可取的每種策略——取0 . . . mi件——均能等價於取若干件代換 以後的物品。另外,取超過mi件的策略必不能出現。
方法是:將第i種物品分成若干件01揹包中的物品,其中每件物品有乙個系 數。這件物品的費用和價值均是原來的費用和價值乘以這個係數。令這些係數 分別為1, 2, 2 ^2 . . . 2 ^ (k−1) , mi − 2^ (k ) + 1,且k是滿足mi − 2 ^ k + 1 > 0的最大整數。
例 如,如果mi為13,則相應的k = 3,這種最多取13件的物品應被分成係數分別 為1, 2, 4, 6的四件物品。 分成的這幾件物品的係數和為mi,表明不可能取多於mi件的第i種物品。另 外這種方法也能保證對於0 . . . mi間的每乙個整數,均可以用若干個係數的和表 示。這裡演算法正確性的證明可以分0 . . . 2 ^ (k−1)和2 ^ k . . . mi兩段來分別討論得出, 這樣就將第i種物品分成了o(logmi)種物品,將原問題轉化為了複雜度 為o(v * σlogmi) 的01揹包問題,是很大的改進。
#include#includeusing namespace std;
const int maxn = 5005;
int dp[maxn][maxn];
int c[maxn];//第i件物品耗費的空間是ci
int w[maxn];//得到的價值是wi。
int main()
k=(num-k+1);
c[p]=k*cost;
w[p]=k*value;
p++;
} //動態規劃邊界問題
for(int i = 0;i <= n; i++)
for(int i = 1;i <= p; i++)else}}
printf("%d\n",dp[p-1][v]);
} return 0;
}
揹包問題 01揹包 完全揹包 多重揹包
01揹包和完全揹包的區別 01揹包的侷限在於每樣物品只有一種,每個物品都有乙個屬於自己的價值和重量,在給定的物品中選出揹包所能容納的最大重量,要求是價值最大 完全揹包與01揹包的不同在於完全揹包不限制每樣物品的個數,物品的價值和質量都與01揹包一樣,也同樣是求在給定大小的容量中,找出最大價值的選擇 ...
揹包問題(01揹包,完全揹包,多重揹包)
揹包問題 01揹包,完全揹包,多重揹包 近日為以下瑣事煩身 差不多要向學院提交專案申請了,本來是想做個多模式的im系統的,可是跟往屆通過審核的專案比起來,缺乏創新和研究價值,所以在文件上要多做手腳,花點心思。揹包問題,經典有揹包九講。不死族的巫妖王發工資拉,死亡騎士拿到一張n元的鈔票 記住,只有一張...
揹包問題 01揹包,完全揹包,多重揹包
有goods num件物品,max volume的最大裝載量,每種物品只有一件,每種物品都有對應的重量或者說體積volume i 價值value i 求解裝包的最大價值 假設目前已經有 i 1件物品裝在容量為 j 的揹包中,並且得到最大價值package i 1 j 當前裝第i件,那麼討論分兩個角度...