01揹包問題 與 完全揹包

一、01揹包

事例:

有N件物品和一個容量爲V的揹包。第i件物品所佔用容量是v[i],價值是w[i]。求將哪些物品裝入揹包可使總價值最大。

思路:

  1. 要使裝入揹包內的物品價值最大,應優先裝入佔地空間小且價值大的物品。
  2. 我們不妨先找出容積從0到V 的各個容量所裝物品的最優解。(就是指 當揹包容量爲1時裝物品的最優解,當揹包容量爲2時裝物品的最優解······一直到容積爲N時裝物品的最優解)。
  3. 那麼如何求在容積爲 v 時的最優解呢。那麼就是把每種情況都放一下找出最優的。此時要用到的公式是f[j]=max(f[j],f[j-weight[i]]+value[i]);
  4. 下面來講解一下該公式的含義

    f[j] 含義是當揹包容量爲 j 時的價值最優解(即怎樣放物品能使揹包總價值最大)。

    f[j-weight[i]] 含義是在放入第i件物品前揹包價值的最優解。

    那麼f[j-weight[i]]+value[i] 的含義就很簡單了,即放入第i件物品時揹包的價值。

    max(f[j],f[j-weight[i]]+value[i]) 就是比較原本揹包容量爲 j 時的最大價值與現在放第i件物品時揹包價值,取最大值成爲新的“揹包容量爲j時的最優解”(我們可以評出的看到揹包的容量一直 j,沒有改變)。

代碼:

#include <iostream>
#include <cstring>
using namespace std;

const int N=4; //一共有N件物品。
const int V=5; //揹包容量爲V。
int weight[N]={1,2,2,3}; //各個物品的體積。
int value[N]={25,10,20,30};//各個物品的價值。
int f[V+1]; //f[j]意味容積j時的最優解。
int zeroonepack()
{
    int i,j;
    memset(f,0,sizeof(f)); //先把f[]初始化爲0。
    for(i=0;i<N;i++)   //找出容積爲 j 時向背包裏裝物品的最優解
    {
        for(j=V;j>=weight[i];j--)  
        {
            f[j]=max(f[j],f[j-weight[i]]+value[i]); 
            cout << j << " " << f[i] << endl;
        }
    }                 //求最優解結束
    return f[V]; //輸出容積爲V時的最佳解(即揹包裝滿時的最優解)
}
int main()
{
    cout << zeroonepack() << endl; //調用函數
    return 0;
}

注意:

有的題目要求“恰好裝滿揹包”時的最優解,有的題目則並沒有要求必須把揹包裝滿。
如果是第一種問法,要求恰好裝滿揹包,那麼在初始化時除了f[0]爲0,其它f[1..V ]均設爲−∞,這樣就可以保證最終得到的f[V ]是一種恰好裝滿揹包的最優解。

二、完全揹包

事例:

有N種物品和一個容量爲V 的揹包,每種物品都可裝入無限次。第i種物品所佔容量爲v[i],價值是W[i]。求將哪些物品裝入揹包可使總價值最大。

思路:

  1. 可將該問題看成01揹包問題。
  2. 不同點是:
    01揹包是一件物品只能用一次,於是我們從體積爲V開始,倒着減。
    完全揹包是從第1件物品開始,只要體積不超過揹包容量V就可以一直裝,那麼一件物品就可以用好多次。

代碼:

#include <iostream>
#include <cstring>
using namespace std;
const int N=4;
const int V=5;
int weight[N]={1,2,2,3};
int value[V]={25,10,20,30};
int f[V+1];
int completepace()
{
    memset(f,0,sizeof(f));
    int i,j;
    for(i=0;i<=N;i++)
    {
        for(j=weight[i];j<=V;j++)    //從第i件物品開始放
        {
            f[j]=max(f[j],f[j-weight[i]]+value[i]);
            cout << j << " " << f[j] << endl;
        }
        return f[V];
    }
}

int main()
{
    cout << completepace() << endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章