bzoj3875 【Ahoi2014】骑士游戏 spfa处理后效性动规
骑士游戏
【故事背景】
长期的宅男生活中,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
题解:
f[i]表示消灭i号怪物需要的最小花费。
我们每更新一个点A的动规值,就会有若干个点的动规值可能被更新。
即可以分裂出点A的那些点。
于是A出队后一旦动规值被更新了,就把那些点入队。
初始时要把所有点入队,因为它们都可能被更新
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #include<vector> 7 #include<queue> 8 #define N 200007 9 #define ll long long 10 using namespace std; 11 12 vector<int>bc[N];//表示这个怪兽可以变成哪几个怪兽。 13 vector<int>zh[N];//表示该怪兽可以由哪几个怪兽要变成。 14 15 int n,r[N]; 16 ll f[N],s[N],k[N]; 17 bool ins[N]; 18 19 int main() 20 { 21 scanf("%d",&n); 22 int x; 23 for (int i=1;i<=n;i++) 24 { 25 scanf("%lld%lld%d",&s[i],&k[i],&r[i]); 26 for (int j=1;j<=r[i];j++) 27 { 28 scanf("%d",&x); 29 bc[i].push_back(x); 30 zh[x].push_back(i); 31 } 32 } 33 for(int i=1;i<=n;i++) 34 f[i]=k[i]; 35 queue<int>q; 36 for (int i=1;i<=n;i++) 37 q.push(i),ins[i]=1; 38 while(!q.empty()) 39 { 40 int u=q.front();q.pop(); 41 ins[u]=0; 42 ll sp=s[u]; 43 for (int i=0;i<bc[u].size();i++) 44 sp+=f[bc[u][i]]; 45 if (sp>=f[u]) continue; 46 f[u]=sp; 47 for (int i=0;i<zh[u].size();i++) 48 if (!ins[zh[u][i]]) 49 { 50 q.push(zh[u][i]); 51 ins[zh[u][i]]=1; 52 } 53 } 54 printf("%lld\n",f[1]); 55 }