P1462 通往奥格瑞玛的道路[最短路+二分+堆优化]
题目来源:洛谷
题目背景
在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量
有一天他醒来后发现自己居然到了联盟的主城暴风城
在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛
题目描述
在艾泽拉斯,有n个城市。编号为1,2,3,...,n。
城市之间有m条双向的公路,连接着两个城市,从某个城市到另一个城市,会遭到联盟的攻击,进而损失一定的血量。
每次经过一个城市,都会被收取一定的过路费(包括起点和终点)。路上并没有收费站。
假设1为暴风城,n为奥格瑞玛,而他的血量最多为b,出发时他的血量是满的。
歪嘴哦不希望花很多钱,他想知道,在可以到达奥格瑞玛的情况下,他所经过的所有城市中最多的一次收取的费用的最小值是多少。
输入输出格式
输入格式:
第一行3个正整数,n,m,b。分别表示有n个城市,m条公路,歪嘴哦的血量为b。
接下来有n行,每行1个正整数,fi。表示经过城市i,需要交费fi元。
再接下来有m行,每行3个正整数,ai,bi,ci(1<=ai,bi<=n)。表示城市ai和城市bi之间有一条公路,如果从城市ai到城市bi,或者从城市bi到城市ai,会损失ci的血量。
输出格式:
仅一个整数,表示歪嘴哦交费最多的一次的最小值。
如果他无法到达奥格瑞玛,输出AFK。
输入输出样例
4 4 8
8
5
6
10
2 1 2
2 4 1
1 3 4
3 4 3
10
说明
对于60%的数据,满足n≤200,m≤10000,b≤200
对于100%的数据,满足n≤10000,m≤50000,b≤1000000000
对于100%的数据,满足ci≤1000000000,fi≤1000000000,可能有两条边连接着相同的城市。(注意细节)
这道题值得一写啊。。。我卡了差不多十次。每次都是一点点瑕疵。
一开始想着dfs暴力搞定,如你所料,TLE了。。。于是转向求助于dijkstra,看了看书发现最短路可以做这道题,结果是最后骗AFK骗到45分。。。
无奈求助于题解,遂用二分解之。
我解释的挺不清楚的,因为我自己也没有理解透彻,这道题比较绕,容易把最大跟最小还有限制条件一下子搞混了,就全乱了。
解析:
题目有点难理解,先解释一下题目:
对于一个有向图G,有两种信息:一个是每条边的权,一个是每个点的费用。
对于这个给定的有向图G,从1到n的通路是一定的。
限制条件:给定一个值,使得某条1到n的通路的边权之和不大于这个值。
我们假设满足以上限制的这些1到n的通路的集合为S(n)。
对于这个集合S中的每个元素(即每条通路),我们记该路径上点的费用的最大值为另一个集合max(n)。
嘿,有了上面这些数学语言的描述作基础,我们可以很简单的理解题意。
我们就是要求出max集合中的最小值。
思路大概是这样:
我们首先要得到合法的可达的通路,使得歪嘴哦不死,然后就是对这条通路做限制,使得这条通路对应的max尽可能小。
我们知道,可选的点是一定的,所以本题的答案一定在所有点的集合中,为了得到更小的让歪嘴哦不死的一个max,我们有一个解法。
假设所有可选的点是a1,a2,...an,我们就把它们排个序,从大到小来找一个既使得歪嘴哦不死,又使得max尽量小的点费用。
因为要让他尽可能不死,所以我们用最短路算法来尽量让他活下来。
哎,发现了没有,“从大到小来找一个既使得歪嘴哦不死,又使得max尽量小的点费用。”这样一个设定,使得我们可以用二分去解它!
二分的前提是,歪嘴哦不死!
我用了一个dij来判断歪嘴哦在当前点费用限制下会不会死:
bool dijkstra(int limit)
{
memset(v,,sizeof(v));
memset(d,0x3f,sizeof(d));
d[]=;
q.push(make_pair(,));
while(q.size()){
int index=q.top().second;q.pop();
if(v[index]) continue;
v[index]=;
for(int i=head[index];i;i=g[i].next){
int y=g[i].ver,z=g[i].edge;
if(d[y]>d[index]+z&&c[y]<=limit){
d[y]=d[index]+z;
q.push(make_pair(d[y],y));
}
}
}
if(d[n]<=hp) return ;
else return ;
}
这个limit就是我们对这条最短路能走过的点费用最大值的限制。
然后是这个二分:
sort(u+,u+n+);
int l=,r=n,ans=c[n];
while(l<=r){
int mid=(l+r)>>;
if(dijkstra(u[mid]))
{
r=mid-;ans=u[mid];
}
else l=mid+;
}
printf("%d\n",ans);
不做任何关于点费用的限制歪嘴哦都会死的话,那就只能AFK了(他真惨):
if(!dijkstra(INF)){
printf("AFK\n");return ;
}
参考代码:
具体的我就不写注释了,上面已经写的很清楚了。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
#define N 10010
#define INF 0x3fffffff
using namespace std;
int head[N],d[N*],tot,n,m,hp;
int u[N*],c[N*];
bool v[N*];
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
struct node{
int ver,next,edge;
}g[N*];
void add(int x,int y,int val)
{
g[++tot].ver=y,g[tot].edge=val;
g[tot].next=head[x],head[x]=tot;
} bool dijkstra(int limit)
{
memset(v,,sizeof(v));
memset(d,0x3f,sizeof(d));
d[]=;
q.push(make_pair(,));
while(q.size()){
int index=q.top().second;q.pop();
if(v[index]) continue;
v[index]=;
for(int i=head[index];i;i=g[i].next){
int y=g[i].ver,z=g[i].edge;
if(d[y]>d[index]+z&&c[y]<=limit){
d[y]=d[index]+z;
q.push(make_pair(d[y],y));
}
}
}
if(d[n]<=hp) return ;
else return ;
}
int main()
{
scanf("%d%d%d",&n,&m,&hp);
for(int i=;i<=n;i++){
scanf("%d",&c[i]);//到达每个点的费用
u[i]=c[i];//我们额外搞一个数组来二分
}
for(int i=;i<=m;i++){
int x,y,val;
scanf("%d%d%d",&x,&y,&val);//过边损失血量
if(x==y) continue;
add(x,y,val);add(y,x,val);
}
if(!dijkstra(INF)){
printf("AFK\n");return ;
}
sort(u+,u+n+);
int l=,r=n,ans=c[n];
while(l<=r){
int mid=(l+r)>>;
if(dijkstra(u[mid]))
{
r=mid-;ans=u[mid];
}
else l=mid+;
}
printf("%d\n",ans);
return ;
}
2019-05-31 19:07:02
P1462 通往奥格瑞玛的道路[最短路+二分+堆优化]的更多相关文章
- Luogu P1462 通往奥格瑞玛的道路(最短路+二分)
P1462 通往奥格瑞玛的道路 题面 题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己 ...
- P1462 通往奥格瑞玛的道路 最短路
题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛 题目描述 在艾泽拉斯, ...
- 洛谷1462 通往奥格瑞玛的道路 最短路&&二分
SPFA和二分的使用 跑一下最短路看看能不能回到奥格瑞玛,二分收费最多的点 #include<iostream> #include<cstdio> #include<cs ...
- P1462 通往奥格瑞玛的道路 (二分+最短路)
题目 P1462 通往奥格瑞玛的道路 给定\(n\)个点\(m\)条边,每个点上都有点权\(f[i]\),每条边上有边权,找一条道路,使边权和小于给定的数\(b\),并使最大点权最小. 解析 二分一下 ...
- P1462 通往奥格瑞玛的道路(二分答案+最短路)
P1462 通往奥格瑞玛的道路 题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡 ...
- luogu P1462 通往奥格瑞玛的道路--spfa+二分答案
P1462 通往奥格瑞玛的道路 题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡 ...
- 洛谷P1462 通往奥格瑞玛的道路(二分+spfa,二分+Dijkstra)
洛谷P1462 通往奥格瑞玛的道路 二分费用. 用血量花费建图,用单源最短路判断 \(1\) 到 \(n\) 的最短路花费是否小于 \(b\) .二分时需要不断记录合法的 \(mid\) 值. 这里建 ...
- [Luogu P1462] 通往奥格瑞玛的道路 (二分答案+最短路径)
题面 传送门:https://www.luogu.org/problemnew/show/P1462 Solution 这道题如果去除掉经过城市的收费.那么就是裸的最短路 但是题目要求经过城市中最多的 ...
- P1462 通往奥格瑞玛的道路【二分+Dij】
P1462 通往奥格瑞玛的道路 提交 29.89k 通过 6.88k 时间限制 1.00s 内存限制 125.00MB 题目提供者gconeice 难度提高+/省选- 历史分数100 提交记录 查看题 ...
随机推荐
- __init__调用之二
class Bar: def __init__(self,name,age): self.suibian = name #self后的名字是啥,对象就可以调用啥,而不是 __init__ 后括号形参 ...
- AVIator -- Bypass AV tool
前提概要 项目地址:https://github.com/Ch0pin/AVIator AV:全名为AntiVirus,意指为防病毒软件 AVIator是一个后门生成器实用程序,它使用加密和注入技术来 ...
- NMF包的安装
win10 操作系统,R3.4版本 NMF包的下载 source("https://bioconductor.org/biocLite.R") biocLite("Bio ...
- html5 canvas 自定义画图裁剪图片
html5 给我们带来了极大惊喜的canvas标签,有了它我们可以在浏览器客户端处理图片,不需要经过服务器周转.可以实现: 1.照片本地处理,ps有的一些基本功能都有 2.结合js可以实现一些很炫的动 ...
- Android广播机制——初体验
写在前面的话 文章为笔者自己理解 . -如有错误,欢迎指正- <第一行代码>读书笔记 写于2017年10月16日17:00:40 (一). 安卓广播的分类 a.标准广播 标准广播发出以后, ...
- Python02之continue,break语句
Python中的break和continue用法基本一样 break和continue都是用在while和for循环中,而不是跳出if...elif..else的判断语句中,跳出是直接跳出语句所在的w ...
- BJFU——205基于顺序存储结构的图书信息表的排序
#include<stdio.h> #include<stdlib.h> #define MAX 1000 typedef struct{ double no; char na ...
- Django框架1——视图和URL配置
三个命令 1.创建一个django项目 在cmd中:django-admin.py startproject project_name D:\python\django_site>django- ...
- Ubuntu的apt命令详解()deepin linux是在Ubuntu基础上开发的
apt-cache和apt-get是apt包的管理工具,他们根据/etc/apt/sources.list里的软件源地址列表搜索目标软件.并通过维护本地软件包列表来安装和卸载软件. 查看本机是否安装软 ...
- C++进行字母大小写转换
#include <iostream> #include <Windows.h> #include <string> using namespace std; in ...