装饰珠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