题目 (蓝桥杯-装饰珠)
题目描述
在怪物猎人这一款游戏中,玩家可以通过给装备镶嵌不同的装饰珠来获取 相应的技能,以提升自己的战斗能力。
已知猎人身上一共有 6 件装备,每件装备可能有若干个装饰孔,每个装饰孔有各自的等级,可以镶嵌一颗小于等于自身等级的装饰珠 (也可以选择不镶嵌)。
装饰珠有 M 种,编号 1 至 M,分别对应 M 种技能,第 i 种装饰珠的等级为
L
i
L_i
Li,只能镶嵌在等级大于等于
L
i
L_i
Li 的装饰孔中。
对第 i 种技能来说,当装备相应技能的装饰珠数量达到
K
i
K_i
Ki个时,会产生
W
i
(
K
i
)
W_i(K_i)
Wi(Ki)的价值,镶嵌同类技能的数量越多,产生的价值越大,即
W
i
(
K
i
−
1
)
<
W
i
(
K
i
)
W_i(K_{i-1})<W_i(K_i)
Wi(Ki−1)<Wi(Ki)。但每个技能都有上限
P
i
(
1
≤
P
i
≤
7
)
P_i(1≤P_i≤7)
Pi(1≤Pi≤7),当装备的珠子数量超过
P
i
P_i
Pi时,只会产生
W
i
(
P
i
)
W_i(P_i)
Wi(Pi)的价值。
对于给定的装备和装饰珠数据,求解如何镶嵌装饰珠,使得 6 件装备能得到的总价值达到最大。
输入描述
输入的第 1 至 6 行,包含 6 件装备的描述。其中第i行的第一个整数
N
i
N_i
Ni表示第i件装备的装饰孔数量。后面紧接着
N
i
N_i
Ni个整数,分别表示该装备上每个装饰孔的等级L(1≤ L ≤4)。
第 7 行包含一个正整数 M,表示装饰珠 (技能) 种类数量。
第 8 至 M + 7 行,每行描述一种装饰珠 (技能) 的情况。每行的前两个整数
L
j
(
1
≤
L
j
≤
4
)
L_j(1≤ L_j ≤4)
Lj(1≤Lj≤4)和
P
j
(
1
≤
P
j
≤
7
)
P_j(1≤ P_j ≤7)
Pj(1≤Pj≤7)分别表示第 j 种装饰珠的等级和上限。接下来
P
j
P_j
Pj个整数,其中第 k 个数表示装备该中装饰珠数量为 k 时的价值
W
j
(
k
)
W_j(k)
Wj(k)。
其中
1
≤
N
i
≤
50
,
1
≤
M
≤
1
0
4
,
1
≤
W
j
(
k
)
≤
1
0
4
1 ≤ N_i ≤ 50,1 ≤ M ≤ 10^4,1 ≤ W_j(k) ≤ 10^4
1≤Ni≤50,1≤M≤104,1≤Wj(k)≤104。
思路
本题是选择性问题,很显然题目的本质是一个背包问题。6个装备可以看成同一个装备,孔的等级才是关键。
我们观察两个不同的等级的珠子L和L-1。对于L而言它可以放入L ~ 4的孔中,而L-1能放入L-1 ~ 4的孔中。即L的珠子能放的孔,L-1必然可以放,我们就可以将L从大到小进行珠子的枚举,注意每次等级变化会将背包的容量也扩大。
再考虑一个种类的珠子的放入,放入只考虑0 ~
P
i
P_i
Pi,且我们只可能从中选择一个,这就是经典的分组背包问题,所以每一个种类的珠子就是一个分组,仅可选择其中的一个,空间复杂度就为
O
(
6
N
)
O(6N)
O(6N),N为每个装备的最多孔数。
时间复杂度为
O
(
m
log
m
+
m
∗
6
∗
N
∗
7
)
=
O
(
m
log
m
+
2100
m
)
O(m\log{m} +m*6*N*7 ) = O(m\log{m} + 2100m)
O(mlogm+m∗6∗N∗7)=O(mlogm+2100m)
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 305 , M = 1e4+5;
int cnt[5];
int n,m,dp[N];
struct node
{
int l,mx;
int w[8];
bool operator < (const node & t)const
{
return l > t.l;
}
}p[M];
int main()
{
for(int i = 1 ; i <= 6 ; i ++)
{
cin>>n;
int x;
for(int j = 1 ; j <= n ; j ++)
{
cin>>x;
cnt[x]++;
}
}
cin>>m;
for(int i = 1 ; i <= m ; i ++)
{
cin>>p[i].l>>p[i].mx;
for(int j = 1 ; j <= p[i].mx ; j ++)
cin>>p[i].w[j];
}
sort(p+1,p+m+1);
memset(dp, 0x80, sizeof dp), dp[0] = 0;
int ans = 0, sum = 0, i = 1;
for (int L = 4; L >= 1; L--) {
sum += cnt[L];
while(p[i].l == L)
{
for(int k = sum ; k >= 0 ; k --)
{
for(int j = 1 ; j <= p[i].mx ; j ++)
{
if(k >= j)
dp[k] = max(dp[k],dp[k-j]+p[i].w[j]);
}
}
i++;
}
}
for (int i = 0; i <= sum; i++) ans = max(ans, dp[i]);
cout<<ans;
return 0;
}