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
解题报告:
考虑直接DP,显然有后效性,会不断影响到之前的所有结点。那么我们用SPFA维护更新操作,保证每次更新能够使所有可更新的结点被更新。
最开始把所有结点加入队列,因为最开始都可以被更新。
记得开long long
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 #ifdef WIN32 14 #define OT "%I64d" 15 #else 16 #define OT "%lld" 17 #endif 18 using namespace std; 19 typedef long long LL; 20 const int MAXN = 200011; 21 const int MAXM = 4000011; 22 int n,m; 23 LL f[MAXN],g[MAXN];//f[i]表示消灭掉i的最小花费,g[i]表示物理攻击i后并消灭产生新怪物后的开销 24 int first[MAXN],next[MAXM],to[MAXM]; 25 int head[MAXN],ecnt,ccnt; 26 bool vis[MAXN]; 27 queue<int>Q; 28 struct edge{ 29 int next,to; 30 }e[MAXM]; 31 32 inline int getint() 33 { 34 int w=0,q=0; 35 char c=getchar(); 36 while((c<'0' || c>'9') && c!='-') c=getchar(); 37 if (c=='-') q=1, c=getchar(); 38 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); 39 return q ? -w : w; 40 } 41 42 inline LL getlong() 43 { 44 LL w=0,q=0; 45 char c=getchar(); 46 while((c<'0' || c>'9') && c!='-') c=getchar(); 47 if (c=='-') q=1, c=getchar(); 48 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); 49 return q ? -w : w; 50 } 51 52 inline void link(int x,int y){ next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; } 53 54 inline void link2(int x,int y){ e[++ccnt].next=head[x]; head[x]=ccnt; e[ccnt].to=y; } 55 56 inline void SPFA(){ 57 while(!Q.empty()) { 58 int u=Q.front(); Q.pop(); vis[u]=0; 59 if(f[u]<=g[u]) continue;//已经更优 60 for(int i=head[u];i;i=e[i].next) { 61 if(!vis[e[i].to]) vis[e[i].to]=1,Q.push(e[i].to); 62 g[e[i].to]-=f[u]; 63 g[e[i].to]+=g[u]; 64 } 65 f[u]=g[u];//存在更优的策略 66 } 67 } 68 69 inline void work(){ 70 n=getint(); int x; 71 for(int i=1;i<=n;i++) { 72 g[i]=getlong(); f[i]=getlong();//初值定为物理攻击和法力攻击 73 m=getint(); Q.push(i); vis[i]=1; 74 for(int j=1;j<=m;j++) x=getint(),link(i,x),link2(x,i); 75 } 76 for(int i=1;i<=n;i++) for(int j=first[i];j;j=next[j]) g[i]+=f[to[j]]; 77 SPFA(); 78 printf("%lld",f[1]); 79 } 80 81 int main() 82 { 83 work(); 84 return 0; 85 }
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!