[BZOJ3875] [Ahoi2014&Jsoi2014]骑士游戏

题目描述

Description

【故事背景】
长期的宅男生活中,JYY又挖掘出了一款RPG游戏。在这个游戏中JYY会
扮演一个英勇的骑士,用他手中的长剑去杀死入侵村庄的怪兽。
【问题描述】
在这个游戏中,JYY一共有两种攻击方式,一种是普通攻击,一种是法术攻
击。两种攻击方式都会消耗JYY一些体力。采用普通攻击进攻怪兽并不能把怪兽彻底杀死,怪兽的尸体可以变出其他一些新的怪兽,注意一个怪兽可能经过若干次普通攻击后变回一个或更多同样的怪兽;而采用法术攻击则可以彻底将一个怪兽杀死。当然了,一般来说,相比普通攻击,法术攻击会消耗更多的体力值(但由于游戏系统bug,并不保证这一点)。
游戏世界中一共有N种不同的怪兽,分别由1到N编号,现在1号怪兽入
侵村庄了,JYY想知道,最少花费多少体力值才能将所有村庄中的怪兽全部杀死呢?

Input

第一行包含一个整数N。
接下来N行,每行描述一个怪兽的信息;
其中第i行包含若干个整数,前三个整数为Si,Ki和Ri,表示对于i号怪兽,普通攻击需要消耗Si的体力,法术攻击需要消耗Ki的体力,同时i号怪兽死亡后会产生Ri个新的怪兽。表示一个新出现的怪兽编号。同一编号的怪兽可以出现多个。

Output

输出一行一个整数,表示最少需要的体力值。

Sample Input

4
4 27 3 2 3 2
3 5 1 2
1 13 2 4 2
5 6 1 2

Sample Output

26

HINT

【样例说明】
首先用消耗4点体力用普通攻击,然后出现的怪兽编号是2,2和3。花费10点体力用法术攻击杀死两个编号为2的怪兽。剩下3号怪兽花费1点体力进行普通攻击。此时村庄里的怪兽编号是2和4。最后花费11点体力用法术攻击将这两只怪兽彻底杀死。一共花费的体力是4+5+5+1+5+6=26。
【数据范围】
2<=N<=2*10^5,1<=Ri,Sigma(Ri)<=10^6,1<=Ki,Si<=5*10^14

题目分析

DP 方程很显然 但是发现可能互相更新 也就是说这个DP是有后效性的
怎么办?类似spfa的方法,一个点如果被更新 将它所有的fa再次压入队列进行更新

#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
int n;
vector<int> v[200010];
long long a[200010],b[200010];
int tot,head[200010],to[4000010],net[4000010];
void add(int x,int y) 
{ net[++tot]=head[x],head[x]=tot,to[tot]=y; }
bool vis[200010];
void spfa()
{
    queue<int>q;
    for(int i=1;i<=n;i++) vis[i]=1,q.push(i);
    while(q.size())
    {   
        int x=q.front();
        q.pop(),vis[x]=0;
        long long tmp=a[x];
        for(int i=head[x];i;i=net[i]) tmp+=b[to[i]];
        if(tmp>=b[x])continue;
        b[x]=tmp;
        for(int i=0;i<v[x].size();i++)
            if(!vis[v[x][i]])
                vis[v[x][i]]=1,q.push(v[x][i]);
    }
}
int main()
{
    scanf("%d",&n);
    for(int x,tmp,i=1;i<=n;i++) 
    {
        scanf("%lld%lld%d",&a[i],&b[i],&tmp);
        while(tmp--) scanf("%d",&x),add(i,x),v[x].push_back(i);
    }
    spfa();
    printf("%lld",b[1]);
    return 0;
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注