动态规划应用举例_揹包问题

揹包问题(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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章