原版链接:蓝桥杯真题——装饰珠_Hey XIN的博客-CSDN博客_蓝桥杯装饰珠
题目描述
在怪物猎人这一款游戏中,玩家可以通过给装备镶嵌不同的装饰珠来获取 相应的技能,以提升自己的战斗能力。
已知猎人身上一共有 6 件装备,每件装备可能有若干个装饰孔,每个装饰孔有各自的等级,可以镶嵌一颗小于等于自身等级的装饰珠 (也可以选择不镶嵌)。
装饰珠有 MM 种,编号 1 至 M,分别对应 MM 种技能,第 i 种装饰珠的等级为 Li,只能镶嵌在等级大于等于 L_iLi 的装饰孔中。
对第 ii 种技能来说,当装备相应技能的装饰珠数量达到 K_iKi 个时,会产生 Wi(Ki) 的价值。镶嵌同类技能的数量越多,产生的价值越大,即 Wi(Ki−1)<Wi(Ki)。但每个技能都有上限Pi(1≤Pi≤7),当装备的珠子数量超过 P_iPi 时,只会产生 Wi(Pi) 的价值。
对于给定的装备和装饰珠数据,求解如何镶嵌装饰珠,使得 6 件装备能得到的总价值达到最大。
输入描述
输入的第 1 至 6 行,包含 6 件装备的描述。其中第 ii 行的第一个整数 N_iNi 表示第 ii 件装备的装饰孔数量。后面紧接着 Ni 个整数,分别表示该装备上每个装饰孔的等级 L (1≤L≤4)。
第 7 行包含一个正整数 M,表示装饰珠 (技能) 种类数量。
第 8 至 M + 7 行,每行描述一种装饰珠 (技能) 的情况。每行的前两个整数Lj (1≤Lj≤4) 和 Pj (1≤Pi≤7) 分别表示第 jj 种装饰珠的等级和上限。接下来 Pj 个整数,其中第 k 个数表示该装备中装饰珠数量为 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 装饰珠 W_1(4) + W_2(4) = 5 + 15 = 20。W1(4)+W2(4)=5+15=20。
运行限制
- 最大运行时间:5s
- 最大运行内存: 256M
分析:
这题是个背包问题,我们把输入的数据拆成两个组:
用一个Hole[5]的vector保存对应每个等级的孔有多少个(最高等级是4,这里从下标1开始),然后是用一个L数组保存不同装饰珠的等级,W保存对应L[i]的珠子装x个的价值W[i][x]
vector<int> Hole(5);
int N,tmp,total=0;
for(int i=0;i<6;++i)
{
cin>>N;
for(int j=0;j<N;++j)
{
cin>>tmp;
++Hole[tmp];
++total;
}
}
cin>>N;
vector<int> L(N+1);
vector<vector<int>> W(N+1,vector<int>());
for(int i=1;i<=N;++i)
{
cin>>L[i];
cin>>tmp;
W[i].resize(tmp+1);
for(int j=1;j<=tmp;++j)
{
cin>>W[i][j];
}
}
装饰孔相当于空间,装饰珠是我们要装的东西,这里和背包问题有不同。
第一是等级的限制:
珠子只能装到大于等于它等级的孔中,这限制了我们做的一些顺序。我们用dp[N+1][total+1]大小的向量容器来装dp的结果,N表示珠子的种类,total表示孔的总数,dp[i][j]表示的是从最高等级的往下装到i等级时,有j个孔时的最佳方案,为什么是从最高等级向最低等级呢?因为这里等级是向下兼容的,比如1的可以装到2的孔里,但是2的装不进1的孔里,所以我们反着遍历等级,就不会发生等级的冲突,容量也是依次增大:
for(int level=4;level>=1;--level)
{
sum+=Hole[level];
if(sum==0) continue;
for(int k=1;k<=N;++k)
{
if(L[k]==level)
{
++kind;
for(int i=1;i<=sum;++i)
{
dp[kind][i]=dp[kind-1][i];
}
for(int i=1;i<W[k].size();++i)
{
for(int j=sum;j>=i;--j)
{
dp[kind][j]=max(dp[kind][j],dp[kind-1][j-i]+W[k][i]);
}
}
}
}
}
最后代码如下所示:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main()
{
// 请在此输入您的代码
vector<int> Hole(5);
int N,tmp,total=0;
for(int i=0;i<6;++i)
{
cin>>N;
for(int j=0;j<N;++j)
{
cin>>tmp;
++Hole[tmp];
++total;
}
}
cin>>N;
vector<int> L(N+1);
vector<vector<int>> W(N+1,vector<int>());
for(int i=1;i<=N;++i)
{
cin>>L[i];
cin>>tmp;
W[i].resize(tmp+1);
for(int j=1;j<=tmp;++j)
{
cin>>W[i][j];
}
}
int sum=0,kind=0;
vector<vector<int>> dp(N+1,vector<int>(total+1));
for(int level=4;level>=1;--level)
{
sum+=Hole[level];
if(sum==0) continue;
for(int k=1;k<=N;++k)
{
if(L[k]==level)
{
++kind;
for(int i=1;i<=sum;++i)
{
dp[kind][i]=dp[kind-1][i];
}
for(int i=1;i<W[k].size();++i)
{
for(int j=sum;j>=i;--j)
{
dp[kind][j]=max(dp[kind][j],dp[kind-1][j-i]+W[k][i]);
}
}
}
}
}
cout<<*max_element(dp[kind].begin(),dp[kind].end());
return 0;
}