题目来源:洛谷

题目背景

在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量

有一天他醒来后发现自己居然到了联盟的主城暴风城

在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛

题目描述

在艾泽拉斯,有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。

输入输出样例

输入样例#1:

4 4 8
8
5
6
10
2 1 2
2 4 1
1 3 4
3 4 3
输出样例#1:

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 通往奥格瑞玛的道路[最短路+二分+堆优化]的更多相关文章

  1. Luogu P1462 通往奥格瑞玛的道路(最短路+二分)

    P1462 通往奥格瑞玛的道路 题面 题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己 ...

  2. P1462 通往奥格瑞玛的道路 最短路

    题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛 题目描述 在艾泽拉斯, ...

  3. 洛谷1462 通往奥格瑞玛的道路 最短路&&二分

    SPFA和二分的使用 跑一下最短路看看能不能回到奥格瑞玛,二分收费最多的点 #include<iostream> #include<cstdio> #include<cs ...

  4. P1462 通往奥格瑞玛的道路 (二分+最短路)

    题目 P1462 通往奥格瑞玛的道路 给定\(n\)个点\(m\)条边,每个点上都有点权\(f[i]\),每条边上有边权,找一条道路,使边权和小于给定的数\(b\),并使最大点权最小. 解析 二分一下 ...

  5. P1462 通往奥格瑞玛的道路(二分答案+最短路)

    P1462 通往奥格瑞玛的道路 题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡 ...

  6. luogu P1462 通往奥格瑞玛的道路--spfa+二分答案

    P1462 通往奥格瑞玛的道路 题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡 ...

  7. 洛谷P1462 通往奥格瑞玛的道路(二分+spfa,二分+Dijkstra)

    洛谷P1462 通往奥格瑞玛的道路 二分费用. 用血量花费建图,用单源最短路判断 \(1\) 到 \(n\) 的最短路花费是否小于 \(b\) .二分时需要不断记录合法的 \(mid\) 值. 这里建 ...

  8. [Luogu P1462] 通往奥格瑞玛的道路 (二分答案+最短路径)

    题面 传送门:https://www.luogu.org/problemnew/show/P1462 Solution 这道题如果去除掉经过城市的收费.那么就是裸的最短路 但是题目要求经过城市中最多的 ...

  9. P1462 通往奥格瑞玛的道路【二分+Dij】

    P1462 通往奥格瑞玛的道路 提交 29.89k 通过 6.88k 时间限制 1.00s 内存限制 125.00MB 题目提供者gconeice 难度提高+/省选- 历史分数100 提交记录 查看题 ...

随机推荐

  1. SSH连接服务器时,长时间不操作就会断开的解决方案

    最近在配置服务器相关内容时候,不同的事情导致长时间不操作,页面就断开了连接,不能操作,只能关闭窗口,最后通过以下命令解决. SSH连接linux时,长时间不操作就断开的解决方案: 1.修改/etc/s ...

  2. uinxSocket 与 tcpSocket

    $tpc = stream_socket_client('unix:///tmp/php-cgi.sock');nginx配置中可以用uninx:/tmp/php-.....这种格式,也可用直接uin ...

  3. eclipse设置格式化tab为4个空格和idea一样

  4. Spark 基础操作

    1. Spark 基础 2. Spark Core 3. Spark SQL 4. Spark Streaming 5. Spark 内核机制 6. Spark 性能调优 1. Spark 基础 1. ...

  5. 解决Ubuntu14.04不能打正确拼音--无法选择第二个拼音

    这时候 我们回到桌面 按"ctrl"+"Alt"+"T",打开系统终端,在终端里面输入ibus-daemon -drx并回车 Ref: ht ...

  6. JDK1.8 的 HashMap 源码之文件注释

    文章目录 null 插入,key的位置变化 迭代操作时间 性能因素 负载因子 Comparable 加锁 迭代器修改 null 插入,key的位置变化,迭代操作时间,性能因素,负载因子,Compara ...

  7. 又是a+b

    题目描述: 给定两个整数 a, b (a, b 均不超过 int 类型的表示范围),求出 a + b 的和.输入描述: 多组输入,每组输入为一行,里面有 2 个数 a, b.输出描述: 对于每一组输入 ...

  8. php数组与数据栈相关函数

    php数组可以用栈的角度来操作,这其中包含了如下函数,array_pop(),array_push,array_shift(),array_unshift(). array_pop()函数 将数组的最 ...

  9. python实战项目 — 爬取中国票房网年度电影信息并保存在csv

    import pandas as pd import requests from bs4 import BeautifulSoup import time def spider(url, header ...

  10. Spring常用jar包功能详解

    很多小伙伴包括我自己,在使用spring的时候导入了一堆jar包,但是并不明白每个jar的用途,使用spring的不同功能时也不知该导入哪个jar包,今天记录一下spring各个jar包的含义,供大家 ...