有
N
N
N 件物品和一个容量是
V
V
V 的背包。每件物品只能使用一次。
第
i
i
i 件物品的体积是
v
i
v_i
vi,价值是
w
i
w_i
wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出 字典序最小的方案。这里的字典序是指:所选物品的编号所构成的序列。物品的编号范围是
1
…
N
1…N
1…N。
输入格式
第一行两个整数,
N
,
V
N,V
N,V,用空格隔开,分别表示物品数量和背包容积。
接下来有
N
N
N 行,每行两个整数
v
i
,
w
i
v_i,w_i
vi,wi,用空格隔开,分别表示第 i件物品的体积和价值。
输出格式
输出一行,包含若干个用空格隔开的整数,表示最优解中所选物品的编号序列,且该编号序列的字典序最小。
物品编号范围是
1
…
N
1…N
1…N。
数据范围
0
<
N
,
V
≤
1000
0<N,V≤1000
0<N,V≤1000
0
<
v
i
,
w
i
≤
1000
0<v_i,w_i≤1000
0<vi,wi≤1000
输入样例:
4 5
1 2
2 4
3 4
4 6
输出样例:
1 4
首先对于背包问题求具体方案,首要是求最大价值,其次是具体方案,且题目要求是求字典序最小的顺序,也就是如果总价值最大的方案中, 可以选 1 1 1 一定会要选 1 1 1, 这样才是字典序最小,所以求具体方案时,我们必须从小到大枚举.
状态表示:
f
[
i
]
[
j
]
:
f[i][j] :
f[i][j]: 从第
i
i
i 个物品 到 最后一个物品中选, 且总体积的不超过
j
j
j 的集合
状态属性: 总价值的最大值
状态计算: 选第
i
i
i 个物品 和 不选第
i
i
i 个物品
f[i][j] = max(f[i +1][j], f[i + 1][j - v[i]] + w[i]);
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int f[N][N],v[N],w[N];
int main()
{
int n,m;
cin >> n >> m;
for(int i = 1; i <= n; i ++ ) //读入
cin >> v[i] >> w[i];
for(int i = n; i >= 1; i -- ) //反向枚举,由状态转移方程所决定的
{
for(int j = 0; j <= m; j ++ )
{
f[i][j] = f[i + 1][j]; //当j < v[i]
if(j >= v[i]) f[i][j] = max(f[i + 1][j],f[i + 1][j - v[i]] + w[i]); //状态转移
}
}
int j = m; //初始化体积
for(int i = 1; i <= n; i ++ ) // 从第1个开始选
{
if(j >= v[i] && f[i][j] == f[i + 1][j - v[i]] + w[i]) //如果能选这一个一定要选,不然字典序一定不如选这个的字典序小
{
cout<< i << " ";
j -= v[i];
}
}
}