BZOJ 3875: [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
题解:这题还是很巧妙的,首先对于这道题我们第一眼当然是DP了,当然设dp[i]表示杀死第i号怪物的最小费用,显然杀死他的最小费用是用魔法费用杀死他的最小费用和用普攻杀死他和杀死其儿子们的最小费之和取min,当然这个dp是有后效性的,因为你杀死你这个怪之后显然他有可能产生自己,所以我们可以用spfa解决这个问题,先把最小费设成魔法攻击,然后每更是一次答案,就要把父节点一起放入队列,这样就可以去更新被当前节点更新的节点了。
代码:
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<algorithm> #include<queue> #include<vector> #include<cstring> #define ll long long const int MAXN=200010; using namespace std; ll pu[MAXN],mo[MAXN],n,num=0,tot=0,dp[MAXN],have[MAXN]; vector<ll> shang[MAXN];queue<ll>q; struct edge{ int first; int next; int to; }a[10*MAXN]; void addedge(int from,int to){ a[++num].to=to; a[num].next=a[from].first; a[from].first=num; } void cl(){ memset(pu,0,sizeof(pu)); memset(dp,37,sizeof(dp)); } void spfa(){ for(int i=1;i<=n;i++){ have[i]=1;q.push(i);dp[i]=mo[i]; } while(!q.empty()){ ll now=q.front(),sum=pu[now],len; q.pop(); have[now]=0; for(int i=a[now].first;i;i=a[i].next){ int to=a[i].to; sum+=dp[to]; } if(dp[now]>sum){ dp[now]=sum,len=shang[now].size(); for(int i=0;i<len;i++){ if(!have[shang[now][i]]){ have[shang[now][i]]=1; q.push(shang[now][i]); } } } } } int main(){ cl(); scanf("%d",&n); for(ll i=1;i<=n;i++){ ll x,y,z; scanf("%lld%lld%lld",&x,&y,&z); pu[i]=x,mo[i]=y; for(ll j=1;j<=z;j++){ ll k;scanf("%lld",&k); addedge(i,k); shang[k].push_back(i); } } spfa(); printf("%lld",dp[1]); }