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

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 }

 

posted @ 2016-08-11 14:50  ljh_2000  阅读(323)  评论(0编辑  收藏  举报