目录
背包基础题目:
题目描述
一个旅行者有一个最多能装 M公斤的背包,现在有 N 件物品,它们的重量分别是W1,W2,...,Wn它们的价值分别为C1,C2,...,Cn,求旅行者能获得最大总价值。
输入格式:
第一行两个整数N,M。
接下来N行,为每个商品的重量和价格
输出格式:
一个正整数,表示旅行者能获得的最大总价值。
输入样例:
5 4
1 2
2 4
3 6
4 9
输出样例:
11
提示说明:
题解:
填表法
绘制一个N行,M列的表格,I行J列的一格表示,只含前I个商品,容量为J时的最高价值,基本归纳成这样一个函数来填表:
然后根据函数填表:
0 | 1 | 2 | 3 | 4 | 5 | |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
W1 – 1, V - 2 | 0 | 2 | 2 | 2 | 2 | 2 |
W2 - 2, V – 4 | 0 | 2 | 4 | 6 | 6 | 6 |
W3 - 3, V – 6 | 0 | 2 | 4 | 6 | 8 | 10 |
W4 - 4, V – 9 | 0 | 2 | 4 | 6 | 9 | 11 |
第N行,第M列,就是答案。
接下来,用程序实现(二维数组):
#include <bits/stdc++.h>
using namespace std;
const int N = 5000;
int main() {
int n, m;//n为物品数量,m为背包只能承受的重量
cin >> n >> m;
int w [N + 1], c[N + 1];//w为物品的重量,c为物品的价值
for (int i = 1; i <= n; i ++) cin >> w [i] >> c [i];
//以上为输入部分
int v [N + 1] [N + 1]; //定义二维工作表
memset (v, 0, sizeof (v)); //不要忘了初始化
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= m; j ++) {//遍历表格并填写
if (w [i] > j) v [i] [j] = v [i - 1] [j];//第一种情况直接把上面的移下来
else v [i] [j] = max (v [i - 1] [j], v [i - 1] [j - w [i]] + c [i]);//执行第二种情况
//取最大值
}
}
//以上为填表部分
cout << v [n] [m];
//输出答案
return 0;
//程序结束
}
一点点优化
空间复杂度可以稍微优化,定义工作表为一维数组,一层层覆盖。
程序实现如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 5000;
int main() {
int n, m;//n为物品数量,m为背包只能承受的重量
cin >> n >> m;
int w [N + 1], c[N + 1];//w为物品的重量,c为物品的价值
for (int i = 1; i <= n; i ++) cin >> w [i] >> c [i];
//以上为输入部分
int v [N + 1]; //定义二维工作表
memset (v, 0, sizeof (v)); //不要忘了初始化
for (int i = 1; i <= n; i ++) { //遍历表格必须从后遍历,因为前面会被覆盖
for (int j = m; j >= 1; j --) {//遍历表格并填写
if (w [i] > j) v [j] = max (v [j], v [j - w [i]] + c [i]);//执行第二种情况,取最大值
}
}
//以上为填表部分
cout << v [m];
//输出答案
return 0;
//程序结束
}
注:两个代码均有小错误,无脑抄代码必挂!
欢迎大家到信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)
提交!