【洛谷】【二分答案+最短路】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。

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

输入输出样例

【算法分析:】

问题可以看作:

给定一张图,给定边权和点权,给定一个最大边权,

问,从点1到点n的路径的总长度不大于最大边权时点权的最大值最小

假设一个最大值,问题就变成了

  求出一条经过的点的点权都不大于这个最大值的最短路径,并且这条最短路的长度小于最大边权(生命值为0就GG了)

好像可以二分答案,证一证它的单调性:

当一个数num被选为最大值的时候,如果存在一条“经过的点的点权都不大于这个最大值的最短路径,并且这条最短路的长度小于最大边权”

则num可以选为最大值。

当num变小时,可以经过的城市变少,可选的点数变少,受到的伤害便可能增多,

使受到的伤害尽可能大(但不能超过总生命值),最大的点权值就会尽可能小,

  故num不一定是最优解,所以从[l, mid]内寻找解

  当num作为最大值过小时,就要从[mid + 1, r]中寻找解.

也就是说这道题将伤害视作边权,二分点权最大值,跑最短路松弛的条件多加了一个:松弛的点的点权必须小于最大点权

每次跑完最短路后如果受到的伤害小于血量那么这个最大点权便是一个解.

【代码:】

 1 //通往奥格瑞玛的道路
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 using namespace std;
 6
 7 const int MAXN = 10000 + 1;
 8 const int MAXM = 50000 + 1;
 9 const int INF = 0x3f3f3f3f;
10
11 int n, m, blood;
12 int city[MAXN];
13
14 int edge_num, head[MAXN];
15 struct edge {
16     int len, to, next;
17 }h[MAXM * 2];
18
19 inline void Add(int from, int to, int len) {
20     h[++edge_num].next = head[from];
21     h[edge_num].to = to, h[edge_num].len = len;
22     head[from] = edge_num;
23 }
24
25 inline int read() {
26     int x = 0; char ch = getchar();
27     while(ch < ‘0‘ || ch > ‘9‘) ch = getchar();
28     while(ch >= ‘0‘ && ch <= ‘9‘)
29         x = (x << 3) + (x << 1) + ch - 48, ch = getchar();
30     return x;
31 }
32
33 int fro, rear;
34 int dis[MAXN], que[MAXN * 20];
35 bool in_que[MAXN];
36 void SPFA(int money) {
37     for(int i = 0; i <= n; i++) dis[i] = INF;
38     memset(in_que, 0, sizeof(in_que));
39     in_que[1] = 1, dis[1] = 0;
40     que[fro = rear = 1] = 1;
41     while(fro <= rear) {
42         int x = que[fro++];
43         in_que[x] = 0;
44         for(int i = head[x]; i; i = h[i].next) {
45             int l = h[i].len, y = h[i].to;
46             if(dis[x] + l < dis[y] && city[y] <= money) {
47                 dis[y] = dis[x] + l;
48                 if(!in_que[y]) in_que[y] = 1, que[++rear] =y;
49             }
50         }
51     }
52 }
53
54 inline bool check(int money) {
55     SPFA(money);
56     return dis[n] < blood;
57 }
58 int main() {
59     int l = 0, r = 0;
60     n = read(), m = read(), blood = read();
61     for(int i = 1; i <= n; ++i) {
62         city[i] = read();
63         r = max(r, city[i]);
64     }
65     l = max(city[1], city[n]);
66     for(int i = 1; i <= m; ++i) {
67         int a, b, c;
68         a = read(), b = read(), c = read();
69         if(a != b) {
70             Add(a, b, c);
71             Add(b, a, c);
72         }
73     }
74     if(!check(r)) { puts("AFK"); return 0; }
75     while(l <= r) {
76         int mid = (l + r) >> 1;
77         if(!check(mid)) l = mid + 1;
78         else r = mid - 1;
79     }
80     printf("%d\n", l);
81 }

原文地址:https://www.cnblogs.com/devilk-sjj/p/9042030.html

时间: 2024-07-30 03:55:05

【洛谷】【二分答案+最短路】P1462 通往奥格瑞玛的道路的相关文章

洛谷P1462 通往奥格瑞玛的道路 二分答案+最短路SPFA

洛谷P1462 通往奥格瑞玛的道路二分答案+最短路SPFA 二分交费最多的一次的钱数 然后只将符合要求的边加入图中 如果到终点的最短路大于等于血量 或者直接起点不能到达终点那么说明不符合要求 需要加大答案 时间复杂度 (log答案)* Ek 需要注意如果本来就不能到达 那么直接输出AFK 1 #include <bits/stdc++.h> 2 #define LL long long 3 #define For(i,j,k) for(int i=j;i<=k;i++) 4 using

洛谷P1462 通往奥格瑞玛的道路

P1462 通往奥格瑞玛的道路 219通过 1.2K提交 题目提供者gconeice 标签二分图论洛谷原创 难度提高+/省选- 提交该题 讨论 题解 记录 最新讨论 RE好多.. 到底怎么判断AFK啊 看不懂题目.. 建议修改题目 究竟是血量为负算挂还是生命… 题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛 题目描述 在艾泽拉斯,有n个城市.编号为1,2,3,...,

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

题面 传送门:https://www.luogu.org/problemnew/show/P1462 Solution 这道题如果去除掉经过城市的收费.那么就是裸的最短路 但是题目要求经过城市中最多的一次性收费的最小值,也就是说让经过的最大值尽可能小 那我们可以考虑二分这个最大值 一切收费大于我们二分的值的城市统统不走 在最短路那里改一下就好了 然后就OjbK了 时间复杂度 O(n*logn*log b) Code //Luogu P1462 通往奥格瑞玛的道路 //May,27th,2018

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

题目 P1462 通往奥格瑞玛的道路 给定\(n\)个点\(m\)条边,每个点上都有点权\(f[i]\),每条边上有边权,找一条道路,使边权和小于给定的数\(b\),并使最大点权最小. 解析 二分一下钱,然后跑最短路,判断一下如果只有这么多钱的话能不能到终点(最短路边权和是不是不超过\(b\)),套个最短路板子,套个二分板子,没了. 代码 //二分+最短路 #include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10;

luogu P1462 通往奥格瑞玛的道路

二次联通门 : luogu P1462 通往奥格瑞玛的道路 /* luogu P1462 通往奥格瑞玛的道路 二分答案 + 最短路 二分最大钱数 每次只走小于当前钱数的路 若最后的血量可以 则证明答案可行 就继续二分 */ #include <iostream> #include <cstring> #include <cstdio> #include <queue> #define Max 10005 #define INF 1e7 using names

洛谷P1462通往奥格瑞玛的道路——二分答案最短路

题目:https://www.luogu.org/problemnew/show/P1462 最大值最小问题,二分答案. 代码如下: #include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; int const MAXN=1e5+5; queue<int>q; int n,m,b,cost[MAXN],head[MAXN],

洛谷 P1462 通往奥格瑞玛的道路 Label: 最小化最大值 &amp;&amp; spfa (存多条边示例)

题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛 题目描述 在艾泽拉斯,有n个城市.编号为1,2,3,...,n. 城市之间有m条双向的公路,连接着两个城市,从某个城市到另一个城市,会遭到联盟的攻击,进而损失一定的血量. 没经过一个城市,都会被收取一定的过路费(包括起点和终点).路上并没有收费站. 假设1为暴风城,n为奥格瑞玛,而他的血量最多为b,出发时他的血量是满的.

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

题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛 题目描述 在艾泽拉斯,有n个城市.编号为1,2,3,...,n. 城市之间有m条双向的公路,连接着两个城市,从某个城市到另一个城市,会遭到联盟的攻击,进而损失一定的血量. 每次经过一个城市,都会被收取一定的过路费(包括起点和终点).路上并没有收费站. 假设1为暴风城,n为奥格瑞玛,而他的血量最多为b,出发时他的血量是满的

P1462 通往奥格瑞玛的道路

题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛 题目描述 在艾泽拉斯,有n个城市.编号为1,2,3,...,n. 城市之间有m条双向的公路,连接着两个城市,从某个城市到另一个城市,会遭到联盟的攻击,进而损失一定的血量. 每次经过一个城市,都会被收取一定的过路费(包括起点和终点).路上并没有收费站. 假设1为暴风城,n为奥格瑞玛,而他的血量最多为b,出发时他的血量是满的