JAVA-装饰珠-DP(01背包)详解&&优解法&&原题目-第十一届蓝桥杯省赛b组第二场J题

装饰珠JAVA-DP(01背包)详解&&优解法&&原题目-第十一届蓝桥杯省赛b组第二场J题
先把题目粘粘2.2

题目描述

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

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

装饰珠有 M 种,编号 1 至 M,分别对应 M种技能,第 i种装饰珠的等级为 Li,只能镶嵌在等级大于等于 Li的装饰孔中。对第 i 种技能来说,当装备相应技能的装饰珠数量达到 Ki个时,会产生 Wi(Ki) 的价值。镶嵌同类技能的数量越多,产生的价值越大,即 Wi(Ki − 1) < Wi(Ki),但每个技能都有上限 Pi ( 1 ≤ Pi ≤ 7 )当装备的珠子数量超过 Pi时,只会产生 Wi(Pi) 的价值。对于给定的装备和装饰珠数据,求解如何镶嵌装饰珠,使得 6 件装备能得到的总价值达到最大。

输入描述

输入的第 1 至 6 行,包含 6 件装备的描述。其中第 i 的第一个整数 Ni表示第 i 件装备的装饰孔数量。后面紧接着 Ni 个整数,分别表示该装备上每个装饰孔的等级 Li ( 1 ≤ Li ≤ 4 )。第 7 行包含一个正整数 M,表示装饰珠 (技能) 种类数量。第 8 至 M + 7 行,每行描述一种装饰珠 (技能) 的情况。每行的前两个整数 Lj ( 1 ≤ Lj ≤ 4 ) 和 Pi ( 1 ≤ Pi ≤ 7 ) 分别表示第 jj种装饰珠的等级和上限。接下来 Pj个整数,其中第 k个数表示装备该中装饰珠数量为 k 时的价值 Wj(k)。
​其中:1≤Ni≤50,1≤M≤10 ^4,1≤Wi≤10 ^4
输出描述
输出一行包含一个整数,表示能够得到的最大价值。
输入输出样例
示例

输入

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。W1(4)+W2(4)=5+15=20。

解析

状态转移方程:dp[i][j]=Math.max(dp[i-1][j],dp[i][s]+maxlim)或dp[i][j]=dp[i-1][j];

  • 表示前i种等级宝珠有放入前j个装饰孔得到的最大价值。

  • 情况1:珠孔j等级>=宝珠等级lv2[i],dp[i][j]=Math.max(dp[i-1][j],dp[i][s]+maxlim)。

  • 情况2:珠孔j等级<宝珠等级lv2[i],dp[i][j]=dp[i-1][j]

  • s,表示放入等级为

  • maxlim,表示镶入t2(只有珠孔j等级>=宝珠等级lv2[i],才t2++)个第i种宝珠所得的价值(并且不超过此种宝珠的上限数lim[i]),详情看下面代码喔

  • 以上说明的前k的,都包括k
    *读者可以揣摩一下dp都是从1开始的用意。记得对珠孔进行排列!!

时间复杂度:O(6mt)=3*e6,t=50,m==10000
耗时: 280ms,内存: 33028kb
有错的地方,还望告诉楼主喔(不胜感激!)1.1

1.代码

import java.util.*;
public class Main {
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		while(sc.hasNext()) {
			int lv1[]=new int[52],num[]=new int[7];
			int t=0;
			for (int i = 1; i < 7; i++) {
				int t1=sc.nextInt();
				num[i]=t1;
				for (int j = 1; j <=t1; j++) {
				    lv1[++t]=sc.nextInt();
				}
			}
			int m=sc.nextInt();
			int lv2[]=new int[m+1],dp[][]=new int[m+1][t+1],lim[]=new int[m+1];
			int w[][]=new int[m+1][8];
			for (int i = 1; i <=m; i++) {
				int t1=sc.nextInt();
				lv2[i]=t1;
				t1=sc.nextInt();
				lim[i]=t1;	
				for (int j = 1; j <=t1; j++) {
					w[i][j]=sc.nextInt();
				}
			}
			Arrays.sort(lv1,1,t+1);
			for (int i = 1; i <=m; i++) {
				int t2=0,s=0;
				for (int j = 1; j <=t; j++) {
					if(lv1[j]>=lv2[i]) {
						t2++;
						if(t2==1) s=j-1;	
						int maxlim=t2>lim[i]?w[i][lim[i]]:w[i][t2];
						dp[i][j]=Math.max(dp[i-1][j],dp[i][s]+maxlim);
					}else {
						dp[i][j]=dp[i-1][j];
					}
				}
			}
			
			int max=0;
			for (int i = 1; i <=t; i++) {
				if(dp[m][i]>max) max=dp[m][i];
			}
			System.out.println(max);
		}
	}
}

2.读入数据

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

3.输出

20

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值