簡述一下01背包:
背包容量大小固定,有一些物品,每個物品都有重量和價值兩個屬性,且物品唯一不重復(即同一物品只能放入一個),放入物品的總重量不能超過背包容量 ,求放入背包的物品的總價值最大化。0代表不放入,1代表放入。
可以通過建表的方式實現01背包,非遞歸實現。
如果用c[i]表示 i 號物品的重量,v[i]表示 i 號物品的價值,函數f(i,j)表示在有0,1,2...i 號物品和重量限制 j 時能夠得到的最大價值,表result[i][j]=f(i,j)
那麼可以f(i,j)=max((result[i - 1][j - c[i]] + v[i]),(result[i - 1][j]))查表非遞歸。
考慮如下:
有一個物品,我們需要考慮該不該把他放入背包中,無非放入和不放入兩種情況,那麼我們只需要把兩種情況下的總價值都算出來,然後取較大的一個就可以了。
result[i - 1][j - c[i]] + v[i]:放入的情況
總價值為 有 i-1 個物品且重量上限為當前上限 j 減去 i 號物品的重量時的價值 result[i - 1][j - c[i]] 加上 i 號物品的價值 v[i]
result[i - 1][j]:不放入的情況,總價值和 i-1 個物品時一樣(當前考慮的物品是 i 號物品)
代碼部分:
#include<iostream>
#include<string>
using namespace std;
int c[11]; //重量
int v[11]; //價值
int result[11][1001]; //表
///f()函數,計算在i+1個物品和重量上限j的條件下的最大背包價值
int f(int i,int j) //第i個物品,重量上限j //0號物品即第一個物品
{
if (i == 0&&c[i]<=j) //0號物品且重量小於上限
{
return v[i]; //把0號物品放入背包,背包價值為第0號物品的價值
}
if (i == 0 && c[i] > j) //0號物品且重量大於上限
{
return 0; //物品放不進背包,此時背包為空,背包價值為0
}
//不是0號物品的情況
if (i != 0 && j-c[i] >= 0) //i號物品可以放入背包
{
//判斷放入和不放入兩種情況下背包的價值,選擇價值大的方案
return (result[i - 1][j - c[i]] + v[i]) > result[i - 1][j] ? (result[i - 1][j - c[i]] + v[i]) : result[i - 1][j];
} //把這個物品放入背包 //不放入背包
else //i號物品不可以放入背包
return result[i - 1][j];
}
int getResult(int top, int num)
{
if (num == 0) //有0個物品
return 0;
else
{
for (int i = 0; i < num; i++) //第i個物品
{
for (int j = 0; j <= top; j++) //重量
{
result[i][j] = f(i,j); //建表,result[i][j]表示有0,1,2...i個物品和j的重量限制下的最大背包價值
}
}
return result[num-1][top];
}
}
int main()
{
int top; //背包容量
int num; //物品數量
cout << "輸入格式:上限,數量,每個物品的重量和價值。" << endl;
cin >> top;
cin >> num;
for (int i = 0; i < num; i++) //第i個物品的重量和價值
{
cin >> c[i] >> v[i];
}
cout << getResult(top, num) << endl;
return 0;
}
測試樣例1:
測試樣例2:
測試樣例3: