動態規劃應用舉例_揹包問題

揹包問題(Knapsack Problem)

問題描述

一個旅行者隨身攜帶一個揹包,可以放入揹包的物品有 n 種,每種物品的重量和價值分別爲wi,vi。如果揹包的最大重量限制是 b, 每種物品可以放多個。怎樣選擇放入揹包的物品以使得揹包的價值最大? 設上述wi,vi,b 都是正整數。

問題建模

解是 < x1, x2,…, xn >,其中 xi 是裝入揹包的第 i 種物品個數。
在這裏插入圖片描述
線性規劃問題:由線性條件約束的線性函數取最大或最小的問題。
整數規劃問題:線性規劃問題的變量 xi 都是非負整數。

子問題界定和計算順序

子問題界定:由參數 k 和 y 界定
k:考慮對物品 1, 2, … , k 的選擇。
y:揹包總重量不超過 y。

原始輸入:k = n,y = b。
子問題計算順序:k = 1,2, … , n 對於給定的 k,y = 1, 2, … ,b.

優化函數的遞推方程

Fk(y):裝前 k 種物品,總重不超過 y,揹包達到的最大價值。
在這裏插入圖片描述
在這裏插入圖片描述在這裏插入圖片描述

標記函數

ik(y):裝前k種物品,總重不超y,揹包達到最大價值時裝入物品的最大標號
在這裏插入圖片描述

實例

在這裏插入圖片描述追蹤解
在這裏插入圖片描述

時間複雜度

備忘錄需計算nb項,每項常數時間,計算時間爲O(nb) .

代碼實例

題目描述:
有N件物品和一個容量爲V的揹包。第i件物品的價值是C[i],重量是W[i]。求解將哪些物品裝入揹包可使價值總和最大。

輸入描述:
輸入第一行數 N V (1 <=N <=500) (1<= V <= 10000)
輸入 N 行 兩個數字 代表 C W (1 <= C <= 50000, 1 <= W <=10000)

示例

輸入
5 10
8 6
10 4
4 2
5 4
5 3

輸出
19

代碼實現

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

int main()
{
    int N,V;
    while(cin >> N >> V)
    {
        vector<int> value(N);//存儲每個物品的價值
        vector<int> capacity(N);//存儲每個物品的容量
        for(int i = 0; i < N; ++i)
        {
            cin >> value[i] >> capacity[i];
        }
        vector<vector<int>> dp(N+1,vector<int>(V+1,0));
        //有N+1行,但是從1開始遍歷,所以每行表示每個物品
        //有V+1列,但是從1開始遍歷,所以每列表示從1開始到最大容量 的 各種情況下 的 物品最大價值存儲
        for(int i = 1; i < N+1; ++i)
        {
            for(int j = 1; j < V+1; ++j)
            {
                if(capacity[i-1] > j)//如果不下,那就等於上次的最優存儲
                {//這裏的capacity[i-1]是因爲這裏的i從1開始
                    dp[i][j] = dp[i-1][j];
                }
                else//如果能放下,有兩種情況:1、放 2、不放
                    //放和不放取決於放了之後是否是最優的,於是創建一個臨時變量。
                {//dp[i-1][j-capacity[i-1]]:i-1:上面一行,j-capacity[i-1]:裝了i-1這個物品之後還剩的容量。
                //所以整體就是:當前的tmp_best == 裝了i-1物品的價值 + 裝了這個物品後剩餘的容量還可以裝的最優的方案
                    int tmp_best = value[i-1] + dp[i-1][j-capacity[i-1]];
                    dp[i][j] = max(tmp_best,dp[i-1][j]);
                }
            }
        }
        //返回最後一個元素就是最優的方案
        cout << dp[N][V] << endl;
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章