题意简述:
(n) 个点,(m) 条边,每条边有权值。求一条 (1) 号点到 (n) 号点的路径,要求使得路径中的边权最小值最大。
( exttt{Data Range: }1 le n le 1000, 0< w le 10^6。)
看到最小值最大
,直接二分答案。
二分一个 (mid),只考虑所有边权 (ge mid) 的边,看 (dis_n) 是不是 INF 即可。
时间复杂度 (O(mlog nlog 10^6))。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair <int, int> PII;
inline int gi()
{
int f = 1, x = 0; char c = getchar();
while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return f * x;
}
const int N = 100003, M = N << 1;
int T;
int n, m;
int tot, head[N], ver[M], nxt[M], edge[M];
int dis[N];
bool vis[N];
inline void add(int u, int v, int w)
{
ver[++tot] = v, edge[tot] = w, nxt[tot] = head[u], head[u] = tot;
}
void Dij(int x)
{
priority_queue <PII> q;
q.push(make_pair(0, 1));
memset(vis, 0, sizeof vis);
memset(dis, 0x3f, sizeof dis);
while (!q.empty())
{
int u = q.top().second; q.pop();
if (vis[u]) continue; vis[u] = true;
for (int i = head[u]; i; i = nxt[i])
{
int v = ver[i], w = edge[i];
if (w < x) continue;
if (dis[v] > min(dis[u], w))
{
dis[v] = min(dis[u], w);
q.push(make_pair(-dis[v], v));
}
}
}
}
inline bool check(int x)
{
Dij(x);
if (dis[n] != 0x3f3f3f3f) return true;
return false;
}
int main()
{
T = gi();
int Case = 0;
while (T--)
{
memset(head, 0, sizeof head);
tot = 0;
n = gi(), m = gi();
int l = 1000001, r = 0;
for (int i = 1; i <= m; i+=1)
{
int u = gi(), v = gi(), w = gi();
add(u, v, w), add(v, u, w);
l = min(l, w), r = max(r, w);
}
int ans = 0;
while (l <= r)
{
int mid = (l + r) >> 1;
if (check(mid)) ans = mid, l = mid + 1;
else r = mid - 1;
}
printf("Scenario #%d:
%d
", ++Case, ans);
}
return 0;
}