版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq1965610770/article/details/76769182
题解:
参照 0/1背包 DP。
注意事项:
晶石取值范围为10^13内;
一堆怪中有一只全技能未破防;
存在0消耗的技能;
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
struct skill{
int use;
int atk;
};
ll fight(vector<int> &em,int def,vector<skill> my);
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
int t,t1;
vector<vector<int> > em(11);
vector<skill> my(m);
for(t=0;t<n;t++) /*以防御值划分怪兽*/
{
int hp,def;
scanf("%d%d",&hp,&def);
em[def].push_back(hp);
}
for(t=0;t<m;t++)
scanf("%d%d",&my[t].use,&my[t].atk);
ll s=0;
t = t1 = 0;
for(t=10;t>=0;t--) /*由高防怪开始统计,尽早判断 "-1" 情况*/
{
if(em[t].size() == 0)
continue;
ll j = fight(em[t],t,my);
if(j == -1)
break;
s += j;
}
if(t != -1)
printf("-1\n");
else
printf("%lld\n",s);
}
return 0;
}
ll fight(vector<int> &em,int def,vector<skill> my)
{
int t;
ll s=0;
for(t=0;t<my.size();t++) /*取得各技能实际伤害*/
{
if(my[t].atk > def)
my[t].atk -= def;
else
my[t].atk = 0;
}
int n;
n = my.size();
for(t=0;t<n;t++) /*将0伤害技能排除*/
{
if(my[t].atk == 0)
{
skill ex;
ex = my[t];
my[t] = my[n-1];
my[n-1] = ex;
n--;
t--;
}
}
if(n == 0)
return -1;
vector<vector<ll> > dp(n+1); /* 0/1背包思路,dp[n]储存每列的最少(圣)晶石消耗*/
int hpm = 0; /*其中,行代表怪物的 hp 由 1 到 maxhp,列代表各技能的使用*/
for(t=0;t<em.size();t++)
{
if(hpm < em[t])
hpm = em[t];
}
for(t=0;t<=n;t++)
{
vector<ll> dp2(hpm+1,0);
dp[t] = dp2;
}
for(t=1;t<=hpm;t++)
{
int t1;
int m = 0x3f3f3f3f;
for(t1=0;t1<n;t1++)
{
if(my[t1].atk >= t)
dp[t1][t] = my[t1].use;
else
dp[t1][t] = my[t1].use+dp[n][t-my[t1].atk];
if(m > dp[t1][t])
m = dp[t1][t];
}
dp[n][t] = m;
}
for(t=0;t<em.size();t++)
s += dp[n][em[t]];
return s;
}