📅  最后修改于: 2023-12-03 15:12:47.268000             🧑  作者: Mango
给定一个含有 $n$ 个结点的有向图 $G=(V,E)$,每条边 $(u,v)\in E$ 有权值 $w_{u,v}$。图中还有两个不同的结点 $s$ 和 $t$,请你求出从 $s$ 到 $t$ 的一条路径,使得路径上边权的最大值最小,并输出这个最小值。
第一行包含三个整数 $n,m,S,T$,分别表示结点数量、有向边数量、起点和终点。
接下来 $m$ 行,每行包含三个整数 $u,v,w$,表示一条有向边 $(u,v)$,边权为 $w$。
输出一个整数,表示从 $s$ 到 $t$ 的一条路径,使得路径上边权的最大值最小的最小值。
$1\le n,m\le 10^5$, $1\le w_{u,v}\le 10^9$。
输入:
4 5 1 4
1 2 2
2 4 5
2 3 4
3 4 3
1 3 1
输出:
4
这是一个最短路径问题,但是根据题意我们需要输出的是从 $s$ 到 $t$ 的一条路径,使得路径上边权的最大值最小。 用二分法寻找我们最终想要的边权 $x$,然后判断是否存在一条从 $s$ 到 $t$ 的路径,满足路径上所有边的边权都不大于 $x$。
如果存在这样的路径,则说明当前的二分边界值太大了,需要继续缩小,比当前二分边界小的值也不满足条件;如果不存在这样的路径,则说明当前的二分边界值太小了,需要继续增大,比当前二分边界大的值均满足条件。
这里我们使用 BFS 算法作为寻找是否存在满足条件的路径的工具,每次 BFS 需要用到队列数据结构。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 1e5 + 10, M = 2e5 + 10;
int h[N], e[M], w[M], ne[M], idx;
int n, m, S, T;
int q[N];
bool st[N];
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
bool bfs(int mid)
{
int hh = 0, tt = 0;
memset(st, 0, sizeof st);
q[0] = S, st[S] = true;
while (hh <= tt)
{
int t = q[hh ++ ];
for (int i = h[t]; ~i; i = ne[i])
{
int j = e[i];
if (w[i] >= mid && !st[j])
{
st[j] = true;
q[ ++ tt] = j;
}
}
}
return st[T];
}
int main()
{
memset(h, -1, sizeof h);
cin >> n >> m >> S >> T;
int maxv = 0, minv = 1e9;
for (int i = 0; i < m; i ++ )
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
maxv = max(maxv, c);
minv = min(minv, c);
}
int l = minv, r = maxv;
while (l < r)
{
int mid = l + r + 1 >> 1;
if (bfs(mid)) l = mid;
else r = mid - 1;
}
cout << l << endl;
return 0;
}