题目链接
题意
思路
-
通过观察数据范围可以发现这题用一般的 01背包 方法肯定解不了
-
但是又发现虽然体积的范围很大名单时价值的范围很小
-
于是联想到将原本找最大价值的问题转换为求最小体积
-
定义体积为 v v v,价值为 w w w
-
f i j f_{ij} fij 是选前 i i i 种物品,价值为 j j j 时的最小体积,如果不能凑出该价值就是 正无穷 03 f 3 f 3 f 3 f 03f3f3f3f 03f3f3f3f
-
关系式为 f i j = m i n ( f ( i − 1 ) j , f ( i − 1 ) ( j − w ) + v ) f_{ij} = min(f_{(i - 1)j\ },\ f_{(i - 1)(j - w) }+ v) fij=min(f(i−1)j , f(i−1)(j−w)+v)
-
然后再求满足体积限制的最大价值即可
-
因为要比最小值,所以初始化为正无穷,不用物品时是 0 0 0
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 105, M = 10005;
int f[N][M];
int n, m;
int v[N], w[N];
int main()
{
cin >> n >> m;
memset(f,0x3f3f3f3f,sizeof(f));
f[0][0] = 0;
for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];
for (int i = 1; i <= n; i ++ )
{
for (int j = 0; j < M; j ++ )
{
f[i][j] = f[i - 1][j];
if (j >= w[i])
{
f[i][j] = min(f[i][j], f[i - 1][j - w[i]] + v[i]);
}
}
}
// 找最大价值
int res = 0;
for (int i = M - 1; i >= 0; i -- )
{
if (f[n][i] <= m)
{
res = i;
break;
}
}
cout << res << endl;
return 0;
}
总结
需要好好观察数据范围。