蓝桥杯-装饰珠

题目 (蓝桥杯-装饰珠)

题目描述

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

已知猎人身上一共有 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(Ki1)<Wi(Ki)。但每个技能都有上限 P i ( 1 ≤ P i ≤ 7 ) P_i(1≤P_i≤7) Pi(1Pi7),当装备的珠子数量超过 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(1Lj4) P j ( 1 ≤ P j ≤ 7 ) P_j(1≤ P_j ≤7) Pj(1Pj7)分别表示第 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 1Ni501M1041Wj(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+m6N7)=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;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值