3875: [Ahoi2014]骑士游戏
Time Limit: 30 Sec Memory Limit: 256 MB
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
这真的是一道很妙的题,反正我是没做出来的。
困扰在"一个怪被砍死会长出一堆不同的怪"这个问题上,难道怪物基因都是相同的怎么跑最短路啊。
去网上看了一波题解发现都讲的很少,似乎是因为这题太水?智障选手请过早弃疗。
假设没有环出现,对它是一个DAG,就是一个很水的DP题了,反向拓扑一下。
然后现在有环了。有环就会有什么呢?有后效性。DP是不能解决有后效性的问题的。
但是SPFA可以。SPFA就是完全没有管后效性的算法(所以很容易被卡?)。
设把怪净化掉的最小花费是f。那么就有: f[i]=min(K[i],S[i]+Σf[R]);
所以一个家伙被更新可能会造成前驱的更新。
所以把它的前驱扔进队列直到队列为空输出f[1]是什么算法啊啊啊啊!
咳咳。所以具体实现步骤就是这样:
把所有的点的f赋为K[i]并加入队列。
计算队首的f'。如果比当前优秀,就更新并加入所有前驱。
直到队列空。
其实我很害怕这个东西的复杂度,但是就是过了... ...
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <vector> #include <cstring> #include <queue> #include <complex> #include <stack> #define LL long long int #define dob double using namespace std; const int N = 200010; const int M = 1000010; struct Node{int to,next;}E[M]; int head[N],tot,n,In[N],R[N]; LL S[N],f[N],K[N]; vector<int>G[N]; int gi() { int x=0,res=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();} while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*res; } LL gL() { LL x=0,res=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();} while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*res; } inline void link(int u,int v){ E[++tot]=(Node){v,head[u]}; head[u]=tot; } inline void SPFA() { queue<int>Q;for(int i=1;i<=n;++i)Q.push(In[i]=i); while(!Q.empty()){ int x=Q.front();Q.pop();In[x]=0;LL sum=S[x]; for(int i=0;i<R[x];++i)sum+=f[G[x][i]]; if(sum>=f[x])continue;f[x]=sum; for(int e=head[x];e;e=E[e].next) if(!In[E[e].to])Q.push(E[e].to),In[E[e].to]=1; } } int main() { n=gi(); for(int i=1;i<=n;++i){ S[i]=gL();K[i]=gL();R[i]=gi(); for(int j=1;j<=R[i];++j){ int r=gi(); link(r,i);G[i].push_back(r); } f[i]=K[i]; } SPFA(); printf("%lld ",f[1]); return 0; }