什麼是完全揹包問題?
有N種物品和一個容量爲V的揹包,每種物品都有無限件可用。
第i種物品的體積是c,價值是w。求解將哪些物品裝入揹包可使這些物品的體積總和不超過揹包容量,且價值總和最大。這裏不同之處是每件物品可無限取,這裏就產生了很多可行的優化,比如同體積的有多種物品,則必然可以捨棄價值小的,也可以捨棄體積大於v的。
比較一下01揹包問題:
在M件物品中取出若干件物品放到揹包中,每件物品對應的體積v1,v2,v3,….對應的價值爲w1,w2,w3,,每件物品之多拿一件。
二者的區別就是01揹包裏每件物品至多隻能拿一件,而完全揹包問題中每件物品可以無限拿。
01揹包問題的解決思路是:第i件物品是否放入揹包,取決於總價值的大小。
狀態轉移方程:f[j]=max(f[j],f[j-ti[i]]+v[i]);
for(int i=1;i<=m;i++)
for(j=t;j>=t[i];j--)//從右到左計算
f[j]=max(f[j],f[j-ti[i]]+p[i]);
完全揹包問題也是同樣的思路,只是循環的方式不一樣
for(int i=1;i<=m;i++)
for(int j=ti[i];j<=t;j++)
f[j]=max(f[j],f[j-ti[i]]+v[i]);
下面的題目就是一個完全揹包問題
題目描述
LiYuxiang是個天資聰穎的孩子,他的夢想是成爲世界上最偉大的醫師。爲此,他想拜附近最有威望的醫師爲師。醫師爲了判斷他的資質,給他出了一個難題。醫師把他帶到一個到處都是草藥的山洞裏對他說:“孩子,這個山洞裏有一些不同種類的草藥,採每一種都需要一些時間,每一種也有它自身的價值。我會給你一段時間,在這段時間裏,你可以採到一些草藥。如果你是一個聰明的孩子,你應該可以讓採到的草藥的總價值最大。”
如果你是LiYuxiang,你能完成這個任務嗎?
此題和原題的不同點:
1.每種草藥可以無限制地瘋狂採摘。
2.藥的種類眼花繚亂,採藥時間好長好長啊!師傅等得菊花都謝了!
輸入格式
輸入第一行有兩個整數T(1 <= T <= 100000)和M(1 <= M <= 10000),用一個空格隔開,T代表總共能夠用來採藥的時間,M代表山洞裏的草藥的數目。接下來的M行每行包括兩個在1到10000之間(包括1和10000)的整數,分別表示採摘某種草藥的時間和這種草藥的價值。
輸出格式
輸出一行,這一行只包含一個整數,表示在規定的時間內,可以採到的草藥的最大總價值。
輸入輸出樣例
輸入 #1
70 3
71 100
69 1
1 2
輸出 #1
140
代碼:
#include<iostream>
#include <algorithm>
using namespace std;
int t,m;
int ti[10001],v[10001];
int f[100001];
//這是一個完全揹包問題
//大概明白了,與01揹包不同的是完全揹包問題中每件物品的數量是無限的
//01揹包每件物品只有一個 ,就放一次
//狀態轉移方程到底是怎麼列出來的明白了,就是這個東西放還是不放的問題
//爲什麼,一個順序一個逆序結果就不同了? 需要在捉摸一下
int main(){
cin>>t>>m;
for(int i=1;i<=m;i++)
cin>>ti[i]>>v[i];
//完全揹包的狀態轉移方程
for(int i=1;i<=m;i++)
for(int j=ti[i];j<=t;j++)
f[j]=max(f[j],f[j-ti[i]]+v[i]);
//01揹包的狀態轉移方程
//for(int i=1;i<=m;i++)
//for(int j=t;j>=t[i];j--)
// f[j]=max(f[j],f[j-ti[i]]+v[i]);
cout<<f[t];
return 0;
}