骑士游戏
Time Limit: 30 Sec Memory Limit: 256 MB
[Submit][Status][Discuss]
Description
在这个游戏中,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
4 27 3 2 3 2
3 5 1 2
1 13 2 4 2
5 6 1 2
Sample Output
26
HINT
2<=N<=2*10^5, 1<=Ri,Sigma(Ri)<=10^6, 1<=Ki,Si<=5*10^14
Solution
首先,若是呈现树形结构,我们显然可以得到一个DP:f[i] = min(f[i], Σf[son[i]])(f[i]表示消灭 i 最小花费)。
但是,显然数据会出现有环的情况。所以我们这个DP是有后效性的。
那么我们就可以用Spfa来消除这个后效性,具体就是:若一个点的 f 在某处被更新了,那么把father[i]重新入队计算。
(复杂度BearChild也不会算啊QAQ)
Code
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<queue>
using namespace std;
typedef long long s64; const int ONE = ;
const int MOD = 1e9 + ; int n, x;
s64 f[ONE], unit[ONE]; int next[ONE], first[ONE], go[ONE], tot;
int nextop[ONE], firstop[ONE], goop[ONE], totop; queue <int> q; int get()
{
int res=,Q=; char c;
while( (c=getchar())< || c>)
if(c=='-')Q=-;
if(Q) res=c-;
while((c=getchar())>= && c<=)
res=res*+c-;
return res*Q;
} void Add(int u, int v)
{
next[++tot] = first[u], first[u] = tot, go[tot] = v;
nextop[++totop] = firstop[v], firstop[v] = totop, goop[totop] = u;
} void Spfa()
{
for(int i = ; i <= n; i++) q.push(i);
while(!q.empty())
{
int u = q.front(); q.pop(); s64 res = unit[u];
for(int e = first[u]; e; e = next[e])
res += f[go[e]]; if(res < f[u])
{
f[u] = res;
for(int e = firstop[u]; e; e = nextop[e])
q.push(goop[e]);
}
}
} int main()
{
n = get();
for(int i = ; i <= n; i++)
{
scanf("%lld %lld", &unit[i], &f[i]);
x = get();
while(x--) Add(i, get());
} Spfa(); printf("%lld", f[]);
}