bzoj3875 [Ahoi2014]骑士游戏
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
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
正解:$spfa$。
碰到这种有后效性的$dp$一般可以用$spfa$解决。
我们只要按照$spfa$的思路,如果当前点被更新了,就用它去松弛别的点。
这样按照最短路的思想来更新,是肯定可以获得最优解的。
1 //It is made by wfj_2048~ 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 #include <cstdlib> 6 #include <cstdio> 7 #include <vector> 8 #include <cmath> 9 #include <queue> 10 #include <stack> 11 #include <map> 12 #include <set> 13 #define sz (2000010) 14 #define N (200010) 15 #define il inline 16 #define RG register 17 #define ll long long 18 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) 19 20 using namespace std; 21 22 vector <int> g1[N],g2[N]; 23 queue <int> Q; 24 25 ll s[N],k[N],f[N]; 26 int vis[N],n; 27 28 il ll gi(){ 29 RG ll x=0,q=1; RG char ch=getchar(); 30 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 31 if (ch=='-') q=-1,ch=getchar(); 32 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 33 return q*x; 34 } 35 36 il void work(){ 37 n=gi(); 38 for (RG int i=1,r;i<=n;++i){ 39 s[i]=gi(),k[i]=gi(),r=gi(); 40 for (RG int j=1,x;j<=r;++j) 41 x=gi(),g1[i].push_back(x),g2[x].push_back(i); 42 } 43 for (RG int i=1;i<=n;++i) Q.push(i),vis[i]=1,f[i]=k[i]; 44 while (!Q.empty()){ 45 RG int x=Q.front(); Q.pop(); RG ll sum=s[x]; vis[x]=0; 46 for (RG int i=0;i<g1[x].size();++i) sum+=f[g1[x][i]]; 47 if (f[x]<=sum) continue; f[x]=sum; 48 for (RG int i=0,v;i<g2[x].size();++i){ 49 v=g2[x][i]; 50 if (!vis[v]) Q.push(v),vis[v]=1; 51 } 52 } 53 printf("%lld\n",f[1]); return; 54 } 55 56 int main(){ 57 File("knight"); 58 work(); 59 return 0; 60 }