0-1揹包問題
給定n個重量為w1/w2/w3.../wn
,價值為v1/v2/v3.../vn
的物品,容量為c
的揹包,求這個揹包可以裝下的價值最高的子集,每個物品只能使用一次
w =
//重量v=
// 價值
c = 5 // 容量
#最佳子集為 [2,1,2] 12+10+15 = 37
對每個物品,都有選擇/不選
兩個狀態,這樣解空間就可以描述成乙個狀態樹,
可以很像求子集
的問題,不同的地方就是,子集的重量和需要小於揹包重量,否則需要剪枝
,如2->1->3
不滿足報容量,則3
不可成為2->1
這個子路徑的葉節點,然後統計每乙個子集的價值總和,比較得出最大值即可;
void
backtrack
(vector<
int> w,vector<
int> v,
int c,
int index,
int& res,
int val)
if(c >= w[index]
)backtrack
(w,v,c,index+
1,res,val);}
intmain()
; vector<
int> v =
;int res =
0,c=5;
backtrack
(w,v,c,
0,res,0)
; cout<
return0;
}
因為上述方法會存在很多重複子問題的計算,所以我們可以儲存子問題計算的結果,從而達到剪枝的效果
int
backtrack2
(vector<
int> w,vector<
int> v,
int c,
int index,
int val,vector
int>>
& memo)
if(memo[index]
[c]!=-1
)return memo[index]
[c];
int aa =0;
if(c >= w[index]
) aa =
max(aa,
backtrack2
(w,v,c,index+
1,val,memo));
memo[index]
[c]= aa;
return aa;
}int
main()
; vector<
int> v =
;int res =0;
vector
int>>
memo
(w.size()
,vector<
int>(6
,-1)
);res =
backtrack2
(w,v,5,
0,0,memo)
; cout<
return0;
}
我們可以使用乙個二維陣列dp[n][c+1]
,表示第幾個物體 在c容量下的價值;
則dp[i][j] = max(dp[i-1][j] , dp[i-1][j-w[i] ] + v[i])
表示w[i]
第i
個物體不裝入揹包的話,則直接由上一層價值傳遞,如果w[i]
裝入揹包的話,則由dp[i-1][j-w[i]]
上一層 減去物體重量時的價值 + 物體本身的價值,取兩者大,**示意圖如下:
| 揹包容量
----------
物體id |
*/
給定乙個僅包含正整數的非空陣列,確定該陣列是否可以分成兩部分,要求兩部分的和相等
[1,2,3,6] -->
[1,2,3],[6]
int
dfs_dp
(vector<
int> w ,
int c)
}for
(auto i:dp)
return dp[n-1]
[c];
}int
main()
; bool flag =
dfs_dp
(v1,6)
; cout<
return0;
}/*0 1 0 0 0 0 0
0 1 0 1 0 0 0
0 1 0 1 1 0 1
0 1 0 1 1 0 1
*/
揹包問題 01揹包問題
n個物品,總體積是v,每個物品的體積的vi,每個物品的最大價值是wi,在不超過v的體積下求最大價值 eg揹包容積為 5 物品數量為 4 物品的體積分別為 物品的價值分別為 思路定義乙個二位陣列int f new int n 1 v 1 f i j 就表示在1 i個物品中選取體積小於v的情況的最大價值...
揹包問題 01揹包
有n件物品和乙個容量為v的揹包。第i件物品的重量是c i 價值是w i 求解將哪些物品裝入揹包可使價值總和最大。01揹包中的 01 就是一種物品只有1件,你可以選擇放進去揹包即1,也可以選擇不放入揹包中即0。include include using namespace std const int ...
揹包問題(01揹包)
1085 揹包問題 在n件物品取出若干件放在容量為w的揹包裡,每件物品的體積為w1,w2 wn wi為整數 與之相對應的價值為p1,p2 pn pi為整數 求揹包能夠容納的最大價值。input 第1行,2個整數,n和w中間用空格隔開。n為物品的數量,w為揹包的容量。1 n 100,1 w 10000...