给定一个包含 n 个节点和 m 条边的图,每条边有一个权值。 你的任务是回答 k 个询问,每个询问包含两个正整数 s 和 t 表示起点和终点,要求寻找从 s 到 t 的一条路径,使得路径上权值最大的一条边权值最小。
Input
第一行包含三个整数 n 、m 、k ,分别表示 n 个节点, m 条路径, k 个询问。 接下来 m 行,每行三个整数 u , v , w, 表示一个由 u 到 v 的长度为 w 的双向边。 再接下来 k 行,每行两个整数 s , t,表示询问从 s 连接到 t 的所有路径中单边长度最大值的最小值。
Output
输出包含 k 行,每一行包含一个整数 p 。p 表示 s 连接到 t 的所有路径中单边长度最大值的最小值。另外,如果 s 到 t 没有路径相连通,输出 -1 即可。
Sample Input
8 11 3 1 2 10 2 5 50 3 4 60 7 5 60 3 6 30 1 5 30 6 7 20 1 7 70 2 3 20 3 5 40 2 6 90 1 7 2 8 6 2
Sample Output
30 -1 30
思路:
这道题最初没想到用最小生成树,看了题解才发现kruskal居然还有这用途,让边从小到大排序,之后一个一个加边,如果两条边通过当前边而连接,说明此边边权即为让两点相连单边长度最大值的最小值。
代码:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<math.h>
#include<map>
using namespace std;
const int N = 1e5;
struct edge
{
int x;
int y;
int w;
}eg[N];
struct data
{
int x;
int y;
}qur[1100];
int cnt = 0;
int n, m, k, f[1100], ans[1100];
int father(int x)
{
if (x != f[x]) f[x] = father(f[x]);
return f[x];
}
bool cmp(const struct edge& a, const struct edge& b)
{
return a.w < b.w;
}
int main()
{
cin >> n >> m >> k;
for (int i = 1; i <= n; i++)
f[i] = i;
for (int i = 1; i <= m; i++)
{
int x, y, w;
scanf("%d%d%d", &x, &y, &w);
eg[i].x = x;
eg[i].y = y;
eg[i].w = w;
}
for (int i = 1; i <= k; i++)
{
int x, y;
scanf("%d%d", &x, &y);
qur[i].x = x;
qur[i].y = y;
}
sort(eg + 1, eg + 1 + m, cmp);
int fa, fb;
for (int i = 1; i <= m && cnt < n - 1; i++)
{
fa = father(eg[i].x);
fb = father(eg[i].y);
if (fa == fb) continue;
for (int j = 1; j <= k; j++)
{
if (ans[j]) continue;
int fx = father(qur[j].x), fy = father(qur[j].y);
if ((fx == fa && fy == fb) || (fx == fb && fy == fa))
ans[j] = eg[i].w;
}
f[fa] = fb;
cnt++;
}
for (int i = 1; i <= k; i++)
{
if (ans[i])
printf("%d\n", ans[i]);
else
printf("-1\n");
}
return 0;
}