动态规划(3): 0-1背包问题

本文详细解析了0-1背包问题的数学模型,包括问题描述、最优解结构、状态定义与状态转移方程,以及如何通过递归逻辑求解最大价值。提供了完整的C语言实现代码,帮助读者深入理解并掌握0-1背包问题的解决方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 问题描述

输入: n组输入<vi, wi>(vi, wi > 0)(value 价值, weight 重量), 最大重量 C;
输出: 一组代表选择的序列<x1, x2, …, xn>, 其中 xi ∈ {0, 1}, 即代表选择 / 不选择,使得下面两个条件成立:Σi=1nwixi≤C\Sigma_{i = 1}^{n} w_ix_i ≤ CΣi=1nwixiCmaxΣi=1nviximax\Sigma_{i = 1}^{n} v_ix_imaxΣi=1nvixi
(下面用这两个方程来代指某个0-1背包问题)

2.问题求解

2.1 最优解的结构

设<x1, x2, …, xn>是Σi=1nwixi≤C\Sigma_{i = 1}^{n} w_ix_i ≤ CΣi=1nwixiCmaxΣi=1nviximax\Sigma_{i = 1}^{n} v_ix_imaxΣi=1nvixi的一组最优解,则<x1, x2, …, xn-1>是Σi=1n−1wixi≤C−wnxn\Sigma_{i = 1}^{n - 1} w_ix_i ≤ C - w_nx_nΣi=1n1wixiCwnxnmaxΣi=1n−1viximax\Sigma_{i = 1}^{n - 1} v_ix_imaxΣi=1n1vixi的一组最优解.注意到前后两组方程在最大重量输入规模上有差异,因此有状态定义如下:

2.2 状态定义及状态转移方程

定义m[i][w]m[i][w]m[i][w]为限制输入规模[1,i][1, i][1,i]且限制最大重量www时的最大价值
m[1][w]=0                                                                       (0≤w<w1)m[1][w] = 0~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(0≤w<w_1)m[1][w]=0                                                                       (0w<w1)
m[1][w]=v1                                                                      (w≥w1)m[1][w] = v_1~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(w≥ w_1)m[1][w]=v1                                                                      (ww1)
m[i][w]=m[i−1][w]                                                       (0≤w<wi)m[i][w] = m[i - 1][w]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(0≤w<w_i)m[i][w]=m[i1][w]                                                       (0w<wi)
m[i][w]=max(m[i−1][w],m[i−1][w−wi]+vi)      (w≥wi)m[i][w] = max(m[i - 1][w], m[i - 1][w - w_i] + v_i)~~~~~~(w≥w_i)m[i][w]=max(m[i1][w],m[i1][wwi]+vi)      (wwi)
*前两个方程是递归的基础,后两个方程代表了这样一种递归逻辑: 当最大重量足够装下第i个物品时,遍历第i个物品是否被选择,选择其中值较大者.

2.3 计算

2.4 构造最优解

m[n][C]m[n][C]m[n][C]即为所求

3. 代码

模板题: http://acm.hit.edu.cn/contest/177/problem/E (好像只有我自己能打开, 留给自己复习用吧, 反正也没人看)

#include<stdio.h>

int v[101];
int w[101];
int m[101][10001];

int max(int x, int y) {
	return (x > y ? x : y);
}

int main() {
	int t, tt;
	scanf("%d", &t);
	for (tt = 1; tt <= t; tt++) {
		int n, c;
		scanf("%d %d", &n, &c);
		int i, j;
		for (i = 1; i <= n; ++i) {
			scanf("%d %d", w + i, v + i);
		}
		for (i = 1; i <= n; ++i) {
			for (j = 0; j <= c; ++j) {
				if (i == 1 && j < w[i])
					m[i][j] = 0;
				else if (i == 1 && j >= w[i])
					m[i][j] = v[i];
				else if (i > 1 && j < w[i])
					m[i][j] = m[i - 1][j];
				else
					m[i][j] = max(m[i - 1][j], m[i - 1][j - w[i]] + v[i]);
			}
		}
		printf("Case #%d: %d\n", tt, m[n][c]);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值