蓝桥杯--装饰珠

文章讲述了在怪物猎人游戏中,通过动态规划解决如何镶嵌装饰珠以获得最大战斗能力提升的问题。利用动态规划数组,遍历装备和装饰珠,计算不同配置下的最大价值,最终找到最优解。
摘要由CSDN通过智能技术生成

题目描述

在怪物猎人这一款游戏中,玩家可以通过给装备镶嵌不同的装饰珠来获取 相应的技能,以提升自己的战斗能力。

已知猎人身上一共有 6 件装备,每件装备可能有若干个装饰孔,每个装饰孔有各自的等级,可以镶嵌一颗小于等于自身等级的装饰珠 (也可以选择不镶嵌)。

装饰珠有 M 种,编号 1 至 M,分别对应 M 种技能,第 i种装饰珠的等级为 Li,只能镶嵌在等级大于等于 Li 的装饰孔中。

对第 i 种技能来说,当装备相应技能的装饰珠数量达到 Ki 个时,会产生 Wi(Ki) 的价值。镶嵌同类技能的数量越多,产生的价值越大,即 Wi(Ki−1)<Wi(Ki)。但每个技能都有上限 Pi(1≤Pi≤7),当装备的珠子数量超过 P_iPi 时,只会产生 Wi(Pi) 的价值。

对于给定的装备和装饰珠数据,求解如何镶嵌装饰珠,使得 6 件装备能得到的总价值达到最大。

输入描述

输入的第 1 至 6 行,包含 6 件装备的描述。其中第 ii 行的第一个整数 N_iNi 表示第 ii 件装备的装饰孔数量。后面紧接着 Ni 个整数,分别表示该装备上每个装饰孔的等级 (1≤L≤4)。

第 7 行包含一个正整数 M,表示装饰珠 (技能) 种类数量。

第 8 至 M + 7 行,每行描述一种装饰珠 (技能) 的情况。每行的前两个整数Lj (1≤Lj≤4) 和Pj (1≤Pi≤7) 分别表示第 j 种装饰珠的等级和上限。接下来 Pj 个整数,其中第 kk 个数表示该装备中装饰珠数量为 k 时的价值 Wj(k)。

其中,1≤Ni≤50,1≤M≤104,1≤Wj(k)≤104。

输出描述

输出一行包含一个整数,表示能够得到的最大价值。

输入输出样例

示例

输入
1 1
2 1 2
1 1
2 2 2
1 1
1 3
3
1 5 1 2 3 5 8
2 4 2 4 8 15
3 2 5 10
输出
20
样例说明

按照如下方式镶嵌珠子得到最大价值 18,括号内表示镶嵌的装饰珠的种类编号:

1: (1)
2: (1) (2)
3: (1)
4: (2) (2)
5: (1)
6: (2)

4 颗技能 1 装饰珠,4 颗技能 2 装饰珠 W1(4)+W2(4)=5+15=20。

题目分析

首先数据量很大,不用穷举和模拟算法。这个装与不装的问题,类似背包问题,我们可以选择动态规划来解决这个题。

每次添加一种装饰珠来计算最大价值。

dp[i][j] i代表每一种装饰珠 j代表容量

我们可以得到dp[i][j] = max(dp[i-1][j],dp[i-1][j-k]+W(ik))(k代表第i种装饰珠的选择个数)

算法:

1.从大等级到小等级遍历个等级孔(因为低等级的孔不能装高等级的球)

2.遍历所有的装饰珠

3.如果等级相同则进入动态算法。

  1. 动态每一个孔

  1. 动态容量

4.选取最后的最大值作为答案

输入数据比较大,我们可以选择快速输入来加速算法运行速度。

import java.io.*;
import java.util.Arrays;

public class Main {
    static StreamTokenizer re = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    //static Scanner sc = new Scanner(System.in);

    static int nextInt() throws IOException {
        re.nextToken();
        return (int) re.nval;
    }

    public static void main(String[] args) throws IOException {
        int[] canPut = new int[5];//各等级孔的数量
        int size = 0;// 想要的孔
        for (int i = 0; i < 6; i++) {//统计孔数量
            int n = nextInt();
            for (int j = 0; j < n; j++) {
                canPut[nextInt()]++;
                size++;
            }
        }

        int type = nextInt();// 球种类的数目
        int[][] data = new int[type + 1][size + 1];//动态规划数组
        int[][] worth = new int[type + 1][9];//0:等级 1:数量 记录球
        for (int i = 1; i <= type; i++) {
            worth[i][0] = nextInt();
            worth[i][1] = nextInt();
            for (int j = 2; j < worth[i][1]+2; j++) {
                worth[i][j] = nextInt();
            }
        }

        int curSize = 0; // 记录大于等于等级的珠子数目
        int index = 1; // 记录已经算过的珠子
        for (int i = 4; i >= 1; i--) {
            if (canPut[i] == 0) continue;//如果没有球就跳过
            curSize += canPut[i];
            for (int x = 1; x < worth.length; x++) { //遍历worth(所有种类的球)表,拿出等级匹配的
                if (worth[x][0] == i) { //当前物品可放
                    for (int y = 1; y <= curSize; y++) {//y:容量 遍历所有的能装的孔
                        int max = data[index - 1][y];
                        for (int count = 1; count <= Math.min(y, worth[x][1]); count++) {
                            max = Math.max(max, data[index - 1][y - count] + worth[x][count + 1]);//当前物品放若干个都进行判断
                        }
                        data[index][y] = max;
                    }
                    index++;
                }
            }
        }
        Arrays.sort(data[index-1]);
        System.out.println((data[index - 1][size]));
    }
}
  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只小余

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值