1.0/1揹包(參考例題:hloj416採藥)
二維解法:
我們設f[i][j]為前i個物品放進容量為j的揹包的最大價值
設體積為v[i],價值為w[i]:
我們可以列舉i(1到n)和j(1到n),不難得出狀態轉移方程
f[i][j]=max
可以知道,當第i件物品不取時,總價值為f[i-1][j]
取得話,總價值為前i-1件物品j-v[i]大小的最大值,j-v[i]是為了給第i件物品騰出空間來訪,加上第i件物品的價值,所以是f[i-1][j-v[i]]+w[i]
**如下:
for (int i=1;i<=n;i++)
for(int v=1;v<=t;v++)
一維解法:
可以知道,每一層i只被覆蓋一次就會浪費,會造成大量空間浪費,因此我們要進行一維陣列的優化。
假如我們直接把二維陣列去掉,會變成這個樣子:
for (int i=1;i<=n;i++)
for(int v=1;v<=t;v++)
因為我們把二維陣列去掉,原來是:前i件物品j個容量的揹包
而現在是:j容量的揹包放進的最大物品,前i件是被忽略的,因此這個方程的一部分:
f[v-c[i]]最優值並不是前i-1個物品的最優值,而是前i件物品的最優值,因為在當v(之前的)=v(當前的)-c[i]且i和當前列舉的i相同時,已經用過第i件物品了,所以是完全揹包,不是01揹包,所以我們可以選擇這麼做:將v逆序列舉,那麼我們就可以確保之前沒有被列舉過了。
最後附上01揹包(採藥)**:
#include
//f[i]表示容量為i的揹包所裝的物品的最大值
using
namespace std;
intmain
(),v[
10000
]={}
,f[10000
]={}
; cin>>v>>n;
//v表示揹包的總容量
for(
int i=
1;i<=n;i++)
cin>>v[i]>>w[i];
//v[i]表示每乙個物品的體積,w[i]為價值
for(
int i=
1;i<=n;i++)
//i列舉物品
for(
int j=v;j>=v[i];j--)
//j列舉體積,到v[i]既可以節約空間複雜度,也可以免去if
f[j]=
max(f[j],f[j-v[i]]+w[i]);
cout<}
2.01揹包的計數:以hloj417集合求和為例:
由題目可知,當n(n+1)%2==1時是無法分解為兩個集合的,因此直接判斷
當n*(n+1)為偶數的時候,我們就可以把它當成01揹包來做
如果是二維:設f[i][j]為前i個數總和為j的集合的方案數,把它想成01揹包,可以這麼得到方程:
如果i不要:那麼方案數是f[i-1][j]
如果i要且可以要:那麼方案數數f[i-1][j-i]
那麼f[i][j]的方案數總和就是f[i-1][j]+f[i-1][j-i].
那麼二維的寫法是這樣的:
for (int i=1;i<=n;i++)
for (int v=1;v<=ans;v++)
那麼其實一維陣列的寫法也是一樣的,自行理解把!
#include
//f[i]表示總和為i的集合方案數
using
namespace std;
intmain();
cin>>n;
sum=n*(n+1)/2
;if(sum%2==
1)sum/=2;
f[0]=1
;for
(int i=
1;i<=n;i++)
for(
int j=sum;j>=i;j--)
f[j]+=f[j-i];
cout
}
揹包DP(01揹包,多重揹包,完全揹包)
從前乙個轉態轉移過來,選還是不選 for int i 1 i n i else f i j f i 1 j 01揹包優化 滾動陣列 for int i 1 i n i for int j m j 1 j if weight i j f j max f j f j weight i value i 優...
ACM 程式設計競賽 DP 01揹包
輸入 n 4 w,v w 5 輸出 7 選擇0,1,3 暴力演算法 o 2 n include using namespace std const int maxn 100 int w maxn v maxn int n,w int rec int i,int j 從第i個商品開始挑選總重量小於j的...
揹包dp之01揹包
現在我們有n個配件,他們有不同的價值.但是我們揹包的容量是有限的,因為我們只有乙個一級包,所以我們最多可以裝v重量的東西.但是為了能更好的吃到雞 不存在的 我們要攜帶更有價值的配件,請問我們最多能拿多少價值的配件來當快遞員呢?輸入的第一行是t,表示有一共要打t場比賽.每組資料由三行組成.第一行包含兩...