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 提交记录 查看题 ...
随机推荐
- git的使用学习(五)git的分支管理
分支管理 分支就是科幻电影里面的平行宇宙,当你正在电脑前努力学习Git的时候,另一个你正在另一个平行宇宙里努力学习SVN. 如果两个平行宇宙互不干扰,那对现在的你也没啥影响.不过,在某个时间点,两个平 ...
- 读取以key=value形式存储的txt文件
代码片段(假设只有3个key=value): public static void main(String[] args) throws IOException { BufferedReader br ...
- 烽火传递【单调队列优化dp】
题目大意: 1.给出长度为n的数组,要求每m个连续的元素之间必须选一个值作为代价,求该数组的最小代价. 题解思路: 1.显然是线性dp,dp[i]表示选择第 i 个元素时的最小总代价.很明显状态转移方 ...
- Elasticsearch配置安装
跨域 elasticsearch-head连接es时会提示连接失败,有可能就是没有开启跨域 http.cors.enabled 是否支持跨域,默认为false http.cors.allow-ori ...
- Servlet 表单及上传文件
// 文件路径 D:\ApacheServer\web_java\HelloWorld\src\com\test\TestServletForm.java package com.test; impo ...
- 关于tomcat9的startup.bat闪退问题&乱码
1.打开apache-tomcat-9.0.22的bin目录 选择图中文件 记事本打开 2.更改文件 setclasspath.bat .0_172\jre 3.保存 startup ----- ...
- Python03之单引号、双引号、三单引号、三双引号
今天在学习字符串的时候,发现字符串有时使用单引号,有时使用双引号,而有时还使用三引号.至此我整理如下: 单引号和双引号区别.三单引号和三双引号也没什么区别. 一: 两单引号之间不可以出现单引号,如果出 ...
- 面试题之web访问突然延迟问题
前言 面试官经常会问平时访问正常的网页突然变慢是什么原因引起的,说明下你排查的思路:我认为这种问题很能考察一个人的综合知识面,既能融通的贯彻知识点,也能展看对每个知识点进行详细的考问. 下面我按我自己 ...
- Django使用指南
一.安装Django 1.命令行安装 pip3 install django(默认安装最新稳定版本) pip3 install django==版本号(指定版本安装) 2.Pycharm安装 在Pyc ...
- BBS项目架构
数据库设计 用户表(用的是auth_user那张表,通过自定义表继承AbstractUser) phone 电话 avatar 头像 create_time 创建时间#外键 blog 一对一个人站点表 ...