HDU2159 FATE(完全背包)

HDU2159 FATE(完全背包)

  • HDU2159 FATE完全背包
    • 题意
    • 思路
    • AC代码

原题地址: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);
            }
        }
    }
}

你可能感兴趣的:(ACM解题报告)