0-1揹包問題單調佇列優化多重揹包(第一次寫調了好久,跪了)dp[i][j]表示前i件物品,體積容量為j的揹包所能獲得的最大價值
決策是第i個物品選不選;
轉移方程 dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+w[i]);
n為物品數量,m為揹包體積
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
if(j-v[i]>=0)dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+w[i]);
可以發現我們的狀態只由上一層前面的狀態決定;
於是我們可以從後面列舉體積這樣我們的狀態轉移還是正確的;
這樣做是為了優化空間
for(int i=1;i<=n;i++)
for(int j=m;~j;j--)
if(j-v[i]>=0)f[j]=max(f[j],f[j-v[i]]+w[i]);
完全揹包指的是每件物品可以無限裝入揹包;
決策是否使用第i件物品,如果使用我們的狀態是由dp[i][j-v[i]]轉移過來
因為物品i還有可能會被選;
dp[i][j]=max(dp[i-1][j],dp[i][j-v[i]]+w[i]);
直接優化方程
//轉移是從上一階段的同v或者這階段的for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
if(j-v[i]>=0)f[j]=max(f[j],f[j-v[i]]+w[i]);
多重揹包就是每件物品由次數限制;
這時候我們考慮二進位制拆分;
二進位制拆分有個性質是000001111它拆成1.
2.4.8可以組成1-15的數
對於每一位我們可以那4個1我們可以選與不選一共16種組合
除去都不選的0000還有15種組合對應1-15
,如1010表示拆分的8和2選進揹包
用換元思想理解;
這樣我們從最低位對乙個數的二進位制進行拆分直到當前位不能被拆而獨立存在
如某物品數量為10;我們可以拆1
2 4發現8不能當作第四物品,所以第四件10-1-2-4=3獨立存在
int v[100000],w[100000],p=0
;for(int i=1;i<=n;i++)
if(s)//
如果還有獨立生成一件換元物品 }//
後續就是0-1揹包數量為p,這裡為了習慣我用n替換p;
for(int i=1;i<=n;i++)
for(int j=m;~j;j--)
if(j-v[i]>=0)f[j]=max(f[j],f[j-v[i]]+w[i]);
//v[i]為物品體積,w[i]為物品價值,c[i]為物品數量,
令b[i]=min(c[i],m/v[i]);//每件物品最多能取幾件
dp[i][j]=max(dp[i][j],dp[i-1][j-k*v[i]]+k*w[i]);
k∈[0,b[i]];
令mod=j%v[i],div=j/v[i];
j=div*v[i]+mod;
上式j-k*v[i]=div*v[i]+mod-k*v[i];
div*v[i]+mod-k*v[i]=v[i]*(div-k)+mod;
換元令k1或者其他數為div-k;
div-k=k1
k1∈[div-b[i],div]一共b[i]+1個數,我們要維護的單調佇列數為b[i]+1;
上式:v[i]*k1+mod+(div-k1)*w[i];
dp[i][j]=max(dp[i][j],dp[i-1][j-k*v[i]]+k*w[i]);
變形dp[i][j]=max(dp[i][j],dp[i-1][k1*v[i]+mod]+(div-k1)*w[i]);
整理一下:dp[i-1][k1*v[i]+mod]-k1*w[i]+div*w[i]; k1∈[div-b[i],j]
上面的轉移方程
觀察前面dp[i][j]到dp[i-1][k1*v[i]+mod]例如j+v[i]與j(modv[i])同餘那我們的方程是在原來轉移上
加上mod mod+v[i] mod+2v[i]....j..j+v[i]這兒所有數(mod v[i])同餘所以我們只要維護b[i]+1長度的滑窗就能慢慢轉移了;
複雜度是o(nv)每個狀態都只會被算一次對於每個i都會通過mod從0 v[i] 2*v[i] --1 1+v[i] 1+2v[i]這樣被填滿到m;
題目acwing 6多重揹包3;
1 #include2using
namespace
std;
3const
int n=1e3+5;4
const
int m=2e4+5;5
inta[n],v[n],c[n],w[n],q[m],f[m],num[m];67
intmain()
8後面其實是q[h]+div*w[i]但是因為div=j/c[i]即 div=(j*v[i]+mod)/v[i]=j,其實因為mod是小於v[i]的28}
29}30 cout
3132
return0;
33 }
1 #include2using
namespace
std;
3const
int n=1e3+5;4
const
int m=2e4+5;5
inta[n],v[n],c[n],w[n],q[m],f[m],num[m];67
intmain()832
}33}34 cout
3536
return0;
37 }
1 #include2//混合揹包問題using
namespace
std;
3const
int n=1e3+5;4
const
int m=2e4+5;5
inta[n],v[n],c[n],w[n],q[m],f[n][m],num[m];67
intmain()
8這樣做廢空間,當然要是開f[2][m]去滾動也行,所以第一種存數值和下標的是最合理的。完結撒花!27}
28}29 cout
3031
return0;
32 }
1acwing 7混合揹包//0-1混完全揹包,如果由多重揹包就二進位制拆成0-1或者單調佇列
2int
f[n],isone[n];
3for(int i=1;i<=n;i++)410
else
1115 }
#includeusing分組揹包就是0-1套0-1揹包;namespace
std;
const
int n=2e3+5
;int
n,v,tot;
intv[n],w[n],s[n],f[n];
intmain()
else
if(cc==0
)
else
if(cc)}}
for(int i=1;i<=tot;i++)
else
}cout
return0;
}
有依賴的揹包
這裡說的依賴不是強制依賴,強制依賴可以把i與其他有關聯的物品打包,看成乙個集合,最後判斷集合的體積是否超出當前容量,超出就沒得取,不超出還是取與不取。
這裡的依賴相當於推廣了分組套0-1;
依賴的物品我們也可取可不取,就對依賴集合單獨做0-1揹包獲取集合中每個v的最大價值;後面就是對每個v再進行列舉,這樣即可;
揹包問題 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件,那麼討論分兩個角度...