【BZOJ3875】[Ahoi2014&Jsoi2014]骑士游戏

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

题解:设f[i]表示杀死一个怪兽的最小花费,显然$f[i]=max(K[i],S[i]+\sum f[j])$。这个DP状态显然是存在环的,我们考虑用SPFA来优化DP。

先建反向图,然后令一开始所有f的初始值都是K,将所有点压入队列,然后边SPFA边DP。我们用g[i]表示上一次从队列中取出i的时候,f[i]的值。那么我们用当前的i去更新它能更新的所有f值,令D=f[i]-g[i],即当前点f的变化量,那么它能更新到的所有点的f值都要-=D。如果一个点在更新后f值大于g值,则将其压入队列。

说这么多其实跟正常的SPFA没什么区别,搞一搞就行。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int maxn=200010;
typedef long long ll;
int n,m,cnt;
int inq[maxn],head[maxn],to[1000010],next[1000010],p[maxn];
ll f[maxn],ff[maxn],g[maxn],v1[maxn],v2[maxn];
queue<int> q;
inline ll rd()
{
ll ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
inline void add(int a,int b)
{
to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
int main()
{
n=rd();
int i,j,a,b,u;
memset(head,-1,sizeof(head));
for(i=1;i<=n;i++)
{
q.push(i),inq[i]=1;
g[i]=v1[i]=rd(),ff[i]=v2[i]=rd(),a=rd();
while(a--) b=rd(),add(b,i);
}
for(i=1;i<=n;i++) for(j=head[i];j!=-1;j=next[j]) g[to[j]]+=v2[i];
for(i=1;i<=n;i++) f[i]=min(g[i],v2[i]);
while(!q.empty())
{
u=q.front(),q.pop(),inq[u]=0;
if(ff[u]==f[u]) continue;
for(i=head[u];i!=-1;i=next[i])// if(min(g[to[i]]+f[u]-ff[u],v2[to[i]])<f[to[i]])
{
g[to[i]]+=f[u]-ff[u],f[to[i]]=min(g[to[i]],v2[to[i]]);
if(f[to[i]]<ff[to[i]]&&!inq[to[i]]) inq[to[i]]=1,q.push(to[i]);
}
ff[u]=f[u];
}
printf("%lld\n",f[1]);
return 0;
}

最新文章

  1. 2016-08-01一起领略ReactJs的风采
  2. 1.kvm的基本搭建
  3. Servlet------(声明式)异常处理
  4. hnoi 2016 省选总结
  5. 利用php CI force_download($filename, $data) 下载.csv 文件解决文件名乱码,文件内容乱码
  6. oracle中exp,imp的使用详解
  7. android113 自定义进度条
  8. 监测div 元素 变动
  9. SQL Convert XML to Table
  10. Windows Phone 8初学者开发—第17部分:Coding4Fun工具包简介
  11. Linux内核——定时器和时间管理
  12. GCC编译选项 -OX[转]
  13. 真win10官方原版ISO下载方法
  14. JDK源码分析(8) StringBuffer &amp; StringBuilder
  15. PLSQL Developer导入dmp文件,一闪而过
  16. velocity模板引擎 -- java.io.FileNotFoundException: velocity.log (Permission denied)
  17. Centos7初始化脚本
  18. swift3 与 OC 语法区别
  19. 大数高精度计算库gmp简介
  20. GAN的文献综述

热门文章

  1. [转]SIGHUP与终端控制
  2. 在做和sap系统集成的一点心得
  3. 微信小程序入门 第一个页面搭建
  4. Js日常笔记之this
  5. Rabbitmq消息队列(三) 工作队列
  6. 我的Android进阶之旅------&amp;gt;Android关于Activity管理的一个简单封装
  7. ArcGIS教程:Geostatistical Analyst 应用演示样例
  8. springboot整合docker部署(两种构建Docker镜像方式)--2019-3-5转
  9. C# 使用IP端口网络打印图片
  10. 在GOOGLE浏览器中模拟移动浏览器 调试Web app