JSOI2014骑士游戏(最短路)
题目背景
长期的宅男生活中,JYY又挖掘出了一款RPG游戏。在这个游戏中JYY会
扮演一个英勇的骑士,用他手中的长剑去杀死入侵村庄的怪兽。
题目描述
在这个游戏中,JYY一共有两种攻击方式,一种是普通攻击,一种是法术攻击。两种攻击方式都会消耗JYY一些体力。采用普通攻击进攻怪兽并不能把怪兽彻底杀死,怪兽的尸体可以变出其他一些新的怪兽,注意一个怪兽可能经过若干次普通攻击后变回一个或更多同样的怪兽;而采用法术攻击则可以彻底将一个怪兽杀死。当然了,一般来说,相比普通攻击,法术攻击会消耗更多的体力值(但由于游戏系统bug,并不保证这一点)。
游戏世界中一共有N种不同的怪兽,分别由1到N编号,现在1号怪兽入侵村庄了,JYY想知道,最少花费多少体力值才能将所有村庄中的怪兽全部杀死呢?
输入输出格式
输入格式:
第一行包含一个整数N。
接下来N行,每行描述一个怪兽的信息;
其中第i行包含若干个整数,前三个整数为Si,Ki和Ri,表示对于i号怪兽,普通攻击需要消耗Si的体力,法术攻击需要消耗Ki的体力,同时i号怪兽死亡后会产生Ri个新的怪兽。表示一个新出现的怪兽编号。同一编号的怪兽可以出现多个。
输出格式:
输出一行一个整数,表示最少需要的体力值。
这道题去年十一小长假考过,当时一脸懵逼不会做,
考虑打怪兽的方式,如果我打的怪兽是只打的,那他分裂后成为的小怪兽一定是小的(这是最优情况下的必然),所以我们按照怪兽的法术抗性加入小根堆中,用一种既像拓扑又像最短路的东西去维护它。
具体做法为:建一张图连向打死后生成的怪兽,在建一张反图,每次取出堆顶后,扫描反边,将反边的入度减去,若如度为0,则扫描正边,看看是否可以更新原来的dp值,若成功更新,则把更新过后的点加入堆。
这样做为什么是对的呢(其实我也不知道)。
显然到最后我们肯定是要用法术攻击的,如果底层的法术攻击代价比上面的点代价还要大,那肯定不是最优解,我们肯定不去取,所以当一个点被更新的条件时当且仅当它的儿子的代价都要比他小时。
下面的话是我这篇题解的参考,并不是我写的。
有种解法是spfa,将法术攻击每个怪兽的体力值当做初始的路径长度,之后优化一个dis之后,将其推进队列,再更新其他怪兽。
如果按照打死每种怪兽的最小体力给怪兽排序的话,可知,假如一个耗体力大的怪兽是被普通攻击了,那么其变成的怪兽一定排在它前面(体力值比他小)。换言之,按照所耗体力值从小到大枚举每个怪兽,由当前枚举过的怪兽更新没有被枚举怪兽的体力值,再找到没有被枚举的怪兽中体力值最小的怪兽继续枚举,枚举的顺序一定是按照打死每种怪兽的最小体力递增排序的,当前体力值也是最小体力值。
每次拿出堆顶,更新刚好达到条件的点(条件即为该点所有出边指向的点都已出堆),如果更优则推入堆中,重复这个过程。
发现暴力判断条件的话时间复杂度显然不对,我们可以用拓扑的思想,建一张反图,每出堆一个点就将其连向的点入度-1,直至入度为0的时候更新该点。
时间复杂度O(nlogn+m)
下面贴代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
#define N 200009
using namespace std;
int n,r[N],x,tot,head[N],head1[N],tot1;
long long d[N],k[N];
bool vis[N];
struct w
{
int n,to;
}an[],an1[];
inline void add1(int u,int v)
{
an1[++tot1].n=head1[u];
an1[tot1].to=v;
head1[u]=tot1;
}
inline void add(int u,int v)
{
an[++tot].n=head[u];
an[tot].to=v;
head[u]=tot;
}
struct ha
{
long long val;
int pos;
};
bool operator < (ha a,ha b)
{
return a.val>b.val;
}
priority_queue<ha>q;
int main()
{
scanf("%d",&n);
for(int i=;i<=n;++i)
{
scanf("%lld%lld%d",&d[i],&k[i],&r[i]);
for(int j=;j<=r[i];++j)
{
scanf("%d",&x);
add(x,i);
add1(i,x);
}
if(!r[i])k[i]=min(k[i],d[i]);
q.push(ha{k[i],i});
}
while(!q.empty())
{
ha u=q.top();q.pop();
if(k[u.pos]<u.val)continue;
if(vis[u.pos])continue;
vis[u.pos]=;
for(int i=head[u.pos];i;i=an[i].n)
{
int v=an[i].to;
r[v]--;
if(r[v]<=&&!vis[v])
{
long long ss=d[v];
for(int j=head1[v];j;j=an1[j].n)
ss+=k[an1[j].to];
if(k[v]>ss)
{
k[v]=ss;
q.push(ha{k[v],v});
}
}
}
}
cout<<k[];
}
JSOI2014骑士游戏(最短路)的更多相关文章
- 【BZOJ3875】[Ahoi2014&Jsoi2014]骑士游戏 SPFA优化DP
[BZOJ3875][Ahoi2014&Jsoi2014]骑士游戏 Description [故事背景] 长期的宅男生活中,JYY又挖掘出了一款RPG游戏.在这个游戏中JYY会扮演一个英勇的 ...
- p4042 [AHOI2014/JSOI2014]骑士游戏
传送门 分析 我们发现对于一个怪物要不然用魔法代价使其无需考虑后续点要么用普通攻击使其转移到他所连的所有点上且所有边大于0 所以我们可以先将一个点的最优代价设为魔法攻击的代价 之后我们倒着跑spfa求 ...
- [BZOJ] 3875: [Ahoi2014&Jsoi2014]骑士游戏
设\(f[x]\)为彻底杀死\(x\)号怪兽的代价 有转移方程 \[ f[x]=min\{k[x],s[x]+\sum f[v]\} \] 其中\(v\)是\(x\)通过普通攻击分裂出的小怪兽 这个东 ...
- 洛谷 P4042 [AHOI2014/JSOI2014]骑士游戏
题意 有\(n\)个怪物,可以消耗\(k\)的代价消灭一个怪物或者消耗\(s\)的代价将它变成另外一个或多个新的怪物,求消灭怪物$的最小代价 思路 \(DP\)+最短路 这几天做的第一道自己能\(yy ...
- 2019.01.22 bzoj3875: [Ahoi2014&Jsoi2014]骑士游戏(spfa+dp)
传送门 题意简述:nnn个怪物,对于编号为iii的怪物可以选择用aia_iai代价将其分裂成另外的bib_ibi个怪物或者用cic_ici代价直接消灭它,现在问消灭编号为1的怪物用的最小代价. ...
- BZOJ3875 AHOI2014/JSOI2014骑士游戏(动态规划)
容易想到设f[i]为杀死i号怪物所消耗的最小体力值,由后继节点更新.然而这显然是有后效性的,正常的dp没法做. 虽然spfa已经死了,但确实还是挺有意思的.只需要用spfa来更新dp值就可以了.dij ...
- bzoj 3875: [Ahoi2014&Jsoi2014]骑士游戏【dp+spfa】
设f[i]为杀死i的最小代价,显然\( f[i]=min(k[i],s[i]+\sum f[to]) \) 但是这个东西有后效性,所以我们使用spfa来做,具体就是每更新一个f[i],就把能被它更新的 ...
- BZOJ3875: [Ahoi2014&Jsoi2014]骑士游戏
[传送门:BZOJ3875] 简要题意: 给出n种怪物,每种怪物都带有三个值,S[i],K[i],R[i],分别表示对他使用普通攻击的花费,使用魔法攻击的花费,对他使用普通攻击后生成的其他怪物. 每种 ...
- LUOGU P4042 [AHOI2014/JSOI2014]骑士游戏 (spfa+dp)
传送门 解题思路 首先设\(f[x]\)表示消灭\(x\)的最小花费,那么转移方程就是 \(f[x]=min(f[x],\sum f[son[x]] +s[x])\),如果这个转移是一个有向无环图,那 ...
随机推荐
- withRouter使用
import React from 'react'; import {Switch,NavLink,Route,Redirect,withRouter} from 'react-router-dom' ...
- eclipse打开package explorer视图
第一步:window-show view-other 第二步:
- AngularJS路由使用案例
AngularJS路由使用案例: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"& ...
- embed标签的flash层级太高问题
因为客户要求,项目得兼容IE的兼容模式 页面到了flash都会遮挡底部悬浮的导航. 改变浮动窗口和embed的层级还是不可以.应该不是层级的关系. 最后百度解决方案:在embed标签内添加了wmode ...
- java学习之—队列
/** * 队列 * Create by Administrator * 2018/6/11 0011 * 下午 3:27 **/ public class Queue { private int m ...
- 关于对ProgressBar定义模板的一些总结
在之前的博客中曾经写到了一篇关于如何定义圆形进度条的文章,今天就ProgressBar再来进行一些总结,首先来介绍一下ProgressBar的结构,ProgressBar控件的模板有两个部分,我们在定 ...
- Guava Cache源码详解
目录 一.引子 二.使用方法 2.1 CacheBuilder有3种失效重载模式 2.2 测试验证 三.源码剖析 3.1 简介 3.2 源码剖析 四.总结 优点: 缺点: 正文 回到顶部 一.引子 缓 ...
- PHP的特质Trait使用
参考: Trait的使用,网站地址https://www.jianshu.com/p/fc053b2d7fd1
- 转载 -- CSS3 中关于 select 下拉列表的样式
截图效果:
- SELECT IDENT_CURRENT(tableName)和自增长列的纠结
项目中要用到一个功能:主表主键为自增长,要求在插入主表数据前先获得主表要插入数据的主键ID值,用在插入子表时获取主键ID.在网上搜了一下,发现SELECT IDENT_CURRENT(TableNam ...