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

1. 问题描述

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

2.问题求解

2.1 最优解的结构

设<x1, x2, …, xn>是 Σ i = 1 n w i x i ≤ C \Sigma_{i = 1}^{n} w_ix_i ≤ C Σi=1nwixiC m a x Σ i = 1 n v i x i max\Sigma_{i = 1}^{n} v_ix_i maxΣi=1nvixi的一组最优解,则<x1, x2, …, xn-1>是 Σ i = 1 n − 1 w i x i ≤ C − w n x n \Sigma_{i = 1}^{n - 1} w_ix_i ≤ C - w_nx_n Σi=1n1wixiCwnxn m a x Σ i = 1 n − 1 v i x i max\Sigma_{i = 1}^{n - 1} v_ix_i maxΣi=1n1vixi的一组最优解.注意到前后两组方程在最大重量输入规模上有差异,因此有状态定义如下:

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

定义 m [ i ] [ w ] m[i][w] m[i][w]为限制输入规模 [ 1 , i ] [1, i] [1,i]且限制最大重量 w w w时的最大价值
m [ 1 ] [ w ] = 0                                                                         ( 0 ≤ w < w 1 ) m[1][w] = 0~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(0≤w<w_1) m[1][w]=0                                                                       (0w<w1)
m [ 1 ] [ w ] = v 1                                                                        ( w ≥ w 1 ) m[1][w] = v_1~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(w≥ w_1) m[1][w]=v1                                                                      (ww1)
m [ i ] [ w ] = m [ i − 1 ] [ w ]                                                         ( 0 ≤ w < w i ) m[i][w] = m[i - 1][w]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(0≤w<w_i) m[i][w]=m[i1][w]                                                       (0w<wi)
m [ i ] [ w ] = m a x ( m [ i − 1 ] [ w ] , m [ i − 1 ] [ w − w i ] + v i )        ( w ≥ w i ) 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]);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值