背包DP——背包问题

给定背包容量C=9,给定四个物品与价值,能装入的最大价值是多少?
物品重量w = { 2,3,4,5 };
物品价值v = { 3,4,6,6 };

dp[i][j]表示对前i种物品,背包容量为j能装入的最大价值。
对于第i+1个物品,可以选择装或者不装两种情况在这里插入图片描述

int backpack(vector<int> w, vector<int> v) {
	int c = 0;
	cin >> c;
	int n = w.size();
	vector<vector<int>>dp(n, vector<int>(c+1, 0));
	for (int i = 1; i < n; i++) {
		for (int j = 0; j <= c; j++) {
			if (j - w[i] >= 0) {
				dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]);
			}
			else {
				dp[i][j] = dp[i - 1][j];
			}
		}
	}
	return dp[n - 1][c];
}

完全背包问题
每个物品可以多次选择。
1.贪心算法,计算v[i]/w[i],尽可能多的选择性价比高的物品。
2.动态规划,考虑每个物品选择i个的最优方案
算法思想:用数组dp[i][j]表示考虑前i个物品,背包容量为j情况下所能装下的最大价值量,dp[i][j] = max(dp[i - 1][j], dp[i - 1][j-kv[i-1]] + kw[i-1]),0=<kv[i-1] <= j。
k=0时表示装不下第i个物品或者不装第i个物品的情况,而dp[i - 1][j-k
v[i-1]] + k*w[i-1]表示能装下第i个物品时,尝试所有可能.
最终结果返回dp[n][c],n表示物品个数,c表示背包容量。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int backpack(vector<int>v, vector<int>w, int c) {
 int n = v.size();//物品数量
 vector<vector<int>> dp(n+1, vector<int>(c + 1, 0));//dp[i][j]考虑前i个物品容量为c的背包能装下的最大价值
 for (int i = 1; i <= n; i++) {//边界问题:i从1开始表示前i个,但是w和v下标都要-1
  for (int j = 1; j <= c; j++) {
   for (int k = 0; k*v[i-1] <= j; k++) {//k=0时表示装不下的可能
    dp[i][j] = max(dp[i - 1][j], dp[i - 1][j-k*v[i-1]] + k*w[i-1]);
   }
  }
 }
 return dp[n][c];
}
int main() {
 vector<int> v = { 1,2,2,3,4 };
 vector<int> w = { 1,2,3,5,7 };
 cout<<backpack(v, w, 8);
 system("Pause");
}

还有一种写法我非常推荐的

int backpack(int n, int c,  vector<int> w, vector<int> v) {
	vector<vector<int>> dp(n+1, vector<int>(c+1, 0));
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= c; j++) {
			if (j - v[i-1] >= 0) {
				dp[i][j] = max(dp[i-1][j], dp[i][j - v[i-1]] + w[i-1]);
			}
			else {
				dp[i][j] = dp[i - 1][j];
			}
		}
	}
	return dp[n][c];
}

这里和01背包的代码区别仅仅是dp[i][j] = max(dp[i-1][j], dp[i][j - v[i-1]] + w[i-1]);
如果装的下的情况下,如果选择装,则在前i件都考虑的情况下的最大值再去装1个第件物品,来达到重复的效果

后记

在我学会凸优化后,我尝试使用线性规划解决01背包问题,结果是可以解决的,但是在这个case里面消耗的时间是DP的1000倍左右。
在这里插入图片描述

from pulp import *
import time

v = [3, 4, 5, 6]
w = [2, 3, 4, 5]
c = 8
n = 4


def knapsack_lp(n, v, w, c):
    # 定义问题
    prob = LpProblem("0/1 Knapsack Problem", LpMaximize)

    # 定义决策变量
    x = LpVariable.dicts("x", list(range(1, n + 1)), cat=LpBinary)

    # 定义目标函数
    prob += lpSum([v[i - 1] * x[i] for i in range(1, n + 1)])

    # 定义约束条件
    prob += lpSum([x[i] for i in range(1, n + 1)]) <= n  # 每个物品最多只能选1次
    prob += lpSum([w[i - 1] * x[i] for i in range(1, n + 1)]) <= c

    # 求解问题
    prob.solve()

    # 输出结果
    result = []
    for i in range(1, n + 1):
        result.append(x[i].varValue)
    return value(prob.objective), result


def knapsack_dp(values, weights, capacity):
    n = len(values)

    # 初始化动态规划表
    dp = [[0 for _ in range(capacity + 1)] for _ in range(n + 1)]

    # 填充动态规划表
    for i in range(1, n + 1):
        for j in range(1, capacity + 1):
            if weights[i - 1] <= j:
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weights[i - 1]] + values[i - 1])
            else:
                dp[i][j] = dp[i - 1][j]

    # 回溯解
    selected_items = []
    i, j = n, capacity
    while i > 0 and j > 0:
        if dp[i][j] != dp[i - 1][j]:
            selected_items.append(i - 1)
            j -= weights[i - 1]
        i -= 1
    selected_items.reverse()

    # 返回结果
    return dp[n][capacity], selected_items

start_time = time.time()
knapsack_lp(n, v, w, c)
end_time = time.time()
lp_time = end_time - start_time
print("lp Elapsed time:", lp_time)

start_time = time.time()
knapsack_dp(v, w, c)
end_time = time.time()
dp_time= end_time - start_time
print("dp Elapsed time:", dp_time)

a = 100 / lp_time
dp_time = a * dp_time
print("lp", 100," ; ", "dp", dp_time)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值