- 0/1 背包的二维费用的问题
分析
-
条件:野生小精灵总数 (大小为 K K K)
-
花费1:精灵球的数量(大小为 N N N )
-
花费2:皮卡丘的体力值 (大小为 M M M)
-
价值:小精灵的数量,每个都表示为 1 1 1
-
状态表示: f [ i , j , k ] f[i,j,k] f[i,j,k] 表示所有只从前 i i i 个物品中选择,且花费1不超过 j j j,花费2不超过 k k k 的选法的最大价值(也就是最大数量)
-
状态计算: f [ i , j , k ] = m a x ( f [ i − 1 , j , k ] , f [ i , j − c o s t 1 [ i ] , k − c o s t 2 [ i ] ] + 1 ) f[i,j,k]=max(f[i-1,j,k],f[i,j-cost_1[i],k-cost_2[i]]+1) f[i,j,k]=max(f[i−1,j,k],f[i,j−cost1[i],k−cost2[i]]+1)
- 分别表示选择第 i i i 个物品和不选
-
求最后一步:最多可以收服的小精灵数量为 f [ K , N , M ] f[K,N,M] f[K,N,M]
实现细节
- 在本题中,我们需要得到的答案是在所有满足的答案中,取到 k k k 的最小值,所以我们还要在 f f f 的第一维和第二维等于 K , N K,N K,N 的时候遍历 k = i → M k=i\to M k=i→M 并换算成剩余体力,求出答案
- 要注意皮卡丘的体力为 0 0 0 时,小精灵不能被收服,所以最多可以收服的小精灵数量实际上为 f [ K , N , M − 1 ] f[K,N,M-1] f[K,N,M−1]
Code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1500;
int n, V1, V2;
int f[maxn][maxn];
int main() {
scanf("%d%d%d", &V1, &V2, &n);
for(int i = 0; i < n; i++) {
int vol1, vol2;
scanf("%d%d", &vol1, &vol2);
for(int j = V1; j >= vol1; j--) {
for(int k = V2 - 1; k >= vol2; k--) { //体力不能为0
f[j][k] = max(f[j][k], f[j - vol1][k - vol2] + 1);
}
}
}
printf("%d ", f[V1][V2 - 1]);
int k = V2 - 1;
while(k > 0 && f[V1][k - 1] == f[V1][V2 - 1]) k--;
printf("%d", V2 - k);
return 0;
}