如果你不知道什麼叫做0-1揹包問題,下面是0-1揹包問題的簡單描述
假設有n件物品
每件物品的體積爲w1, w2……wn
相對應的價值爲 v1, v2.……vn。
01揹包是在n件物品取出若干件放在空間爲total_weight的揹包裏,使得揹包的總體積最大
關於0-1揹包問題沒有優化版本,請看這裏
上面的核心代碼是下面這一段
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= total_weight; j++) {
if (w[i] > j) {
c[i][j] = c[i-1][j];
} else {
if (c[i-1][j] > v[i]+c[i-1][j-w[i]]) {
c[i][j] = c[i-1][j];
}
else {
c[i][j] = v[i] + c[i-1][j-w[i]];
}
}
}
}
每一次c[i][j]改變的值只與c[i-1][x] {x:1...j}有關c[i-1][x]是前一次i循環保存下來的值,因此,可以將c縮減成一維數組
狀態轉移方程轉換爲 c[j] = max(c[j], c[j-w[i]]+v[i]);
並且,我們注意到狀態轉移方程,每一次推導c[i][j]是通過c[i-1][j-w[i]]來推導的,而不是通過c[i][j-w[i]]
因此,j的掃描順序應該改成從大到小
否則,第i次求c數組,必然先求的c[j-w[i]]的值(即c[i][j-w[i]]),再求c[j](即c[i][j])的值
由於j遞增,那麼狀態方程就成爲下面這個樣子了
c[i][j] = max(c[i-1][j], c[i][j-w[i]]+v[i])顯然不符合題意所以,上面的代碼變爲
for (int i = 1; i <= n; i++) {
for (int j = total_weight; j >= 1; j--) {
if (w[i] > j) {
c[j] = c[j]; //表示第i次與第i-1次相等,這裏因爲c[j]本來就保存這上一次的值,所以這裏不需變化
} else {
//說明第i件物品的重量小於揹包的重量,所以可以選擇第i件物品放還是不放
if (c[j] > v[i]+c[j-w[i]]) {
c[j] = c[j];
}
else {
c[j] = v[i] + c[j-w[i]];
}
}
}
}
for (int i = 1; i <= n; i++)
for (int j = total_weight; j >= w[i]; j--)
if (c[j] <= v[i] + c[j-w[i]])
c[j] = v[i] + c[j-w[i]];
如此優美的代碼簡直無法想象!
注意,空間優化版本最後是求解不出來最優解序列的,但是能求出最優解,也就是最大價值