HDU2159 FATE(完全背包)
原题地址:http://acm.hdu.edu.cn/showproblem.php?pid=2159
题意
这是中文题,在此就不再赘述,自己看。
思路
这是一道二维完全背包问题,对于背包问题不太了解的推荐看一下背包九讲,讲的很不错。这里简单介绍一下完全背包,所谓完全背包就是有N个物品,每个物品有无限个,且每个物品的价值为V[i],费用为W[i],现有一个容量为C的背包,问将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
而对于本道题目来说,因为每一种怪都可以杀无限多个,所以是完全背包,且同时因为每杀死一个怪所需要的费用为两种,一种是忍耐度,另一个是已杀怪的数量,所以这同时也是个二维费用背包。
因为这是一个二维费用完全背包,所以我们至少要开一个二维的数组,当然也可以开一个三维数组,但耗费的空间太大,所以此处以二维为例。我们用一个二维数组dp[j][l]
表示每消耗j忍耐度,杀掉l个怪物所能获得的最大经验值,状态转移方程为:dp[j][l] = Math.max(dp[j][l], dp[j - cost[i]][l - 1] + value[i]);
AC代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
/**
* Created with IntelliJ IDEA.
*
* @author wanyu
* @Date: 2018-02-13
* @Time: 12:14
* To change this template use File | Settings | File Templates.
* @desc
*/
public class Main {
public static void main(String[] args) throws IOException {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
while (in.nextToken() != StreamTokenizer.TT_EOF) {
int n = (int) in.nval;//经验值
in.nextToken();
int m = (int) in.nval;//忍耐度
in.nextToken();
int k = (int) in.nval;//怪物的种类
in.nextToken();
int s = (int) in.nval;//最多杀怪数
int[] value = new int[k];//经验值
int[] cost = new int[k];//消费的忍耐度
for (int i = 0; i < k; i++) {
in.nextToken();
value[i] = (int) in.nval;
in.nextToken();
cost[i] = (int) in.nval;
}
int[][] dp = new int[m + 1][s + 1];//消耗m忍耐度,杀掉s个怪物所能获得的最大经验值
for (int i = 0; i < k; i++) {
for (int j = cost[i]; j <= m; j++) {
for (int l = 1; l <= s; l++) {
dp[j][l] = Math.max(dp[j][l], dp[j - cost[i]][l - 1] + value[i]);
}
}
}
if (dp[m][s] >= n) {
//可以升级
w:
for (int i = 0; i <= m; i++) {
for (int j = 0; j <= s; j++) {
if (dp[i][j] >= n) {
System.out.println(m - i);
break w;
}
}
}
} else {
//无法升级
System.out.println(-1);
}
}
}
}