题目描述
有一个局域网,由 n 个设备和 m 条物理连接组成,第 i 条连接的稳定性为wi 。
对于从设备 A 到设备 B 的一条经过了若干个物理连接的路径,我们记这条路径的稳定性为其经过所有连接中稳定性最低的那个。
我们记设备 A 到设备 B 之间通信的稳定性为 A 至 B 的所有可行路径的稳定性中最高的那一条。
给定局域网中的设备的物理连接情况,求出若干组设备 xi 和 yi 之间的通信稳定性。如果两台设备之间不存在任何路径,请输出 −1 。
输入格式
输入的第一行包含三个整数 n, m, q ,分别表示设备数、物理连接数和询问数。
接下来 m 行,每行包含三个整数 ui , vi ,wi ,分别表示 ui 和 vi 之间有一条稳定性为 wi 的物理连接。
接下来 q 行,每行包含两个整数 xi , yi ,表示查询 xi 和 yi 之间的通信稳定性。
输出格式
输出 q 行,每行包含一个整数依次表示每个询问的答案。
样例输入
5 4 3
1 2 5
2 3 6
3 4 1
1 4 3
1 5
2 4
1 3
样例输出
-1
3
5
提示
对于 30% 的评测用例,n, q ≤ 500,m ≤ 1000 ;
对于 60% 的评测用例,n, q ≤ 5000,m ≤ 10000 ;
对于所有评测用例,2 ≤ n, q ≤ 10^5,1 ≤ m ≤ 3 × 10^5,1 ≤ ui , vi , xi , yi ≤ n,1 ≤ wi ≤ 10^6, ui ≠ vi,xi ≠ yi 。
暴力解法
使用 Floyd 算法
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
const int N = 5e3 + 5;
int e[N][N];
int n, m, q;
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
cin >> n >> m >> q;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
if(i == j)
{
e[i][j] = 0;
}
else
{
e[i][j] = -1;
}
}
}
for(int i = 1; i <= m; i++)
{
int u, v, w;
cin >> u >> v >> w;
e[u][v] = max(e[u][v], w);
e[v][u] = max(e[v][u], w);
}
for(int k = 1; k <= n; k++)
{
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
if(i != j && j != k && k != i)
{
e[i][j] = max(e[i][j], min(e[i][k], e[k][j]));
}
}
}
}
for(int i = 1; i <= q; i++)
{
int x, y;
cin >> x >> y;
cout << e[x][y] << endl;
}
return 0;
}
整体思路
使用 Kruskal 重构树,再用倍增法 LCA 寻找最大生成树的最近公共祖先。
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
const int N = 2e5 + 5;
const int M = 3e5 + 5;
int father[N << 1], val[N << 1];
vector<int> edge[N << 1];
int dep[N << 1], fa[N << 1][25], lg[N << 1];
struct node
{
int u;
int v;
int dis;
}e[M];
int n, m, q;
bool cmp(node x, node y)
{
return x.dis > y.dis;
}
int findfather(int v)
{
if(father[v] == v)
{
return v;
}
else
{
int F = findfather(father[v]);
father[v] = F;
return F;
}
}
void Kruskal()
{
for(int i = 1; i < 2 * n; i++)
{
father[i] = i;
}
sort(e + 1, e + 1 + m, cmp);
int idx = n; // 新建节点的编号
for(int i = 1; i <= m; i++)
{
int fu = findfather(e[i].u);
int fv = findfather(e[i].v);
if(fu != fv)
{
val[++idx] = e[i].dis;
edge[idx].push_back(fu);
edge[idx].push_back(fv);
father[fu] = father[fv] = idx;
}
}
}
void dfs(int u, int father)
{
dep[u] = dep[father] + 1;
fa[u][0] = father;
for(int i = 1; i <= lg[dep[u]]; i++)
{
fa[u][i] = fa[fa[u][i - 1]][i - 1];
}
for(int v : edge[u])
{
if(v != father)
{
dfs(v, u);
}
}
}
int lca(int u, int v)
{
if(findfather(u) != findfather(v))
{
return -1;
}
if(dep[u] < dep[v])
{
swap(u, v);
}
for(int i = lg[dep[u] - dep[v]] - 1; i >= 0; i--)
{
if(dep[fa[u][i]] >= dep[v])
{
u = fa[u][i];
}
}
if(u == v)
{
return val[u];
}
for(int i = lg[dep[u]] - 1; i >= 0; i--)
{
if(fa[u][i] != fa[v][i])
{
u = fa[u][i];
v = fa[v][i];
}
}
return val[fa[u][0]];
}
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
cin >> n >> m >> q;
for(int i = 1; i <= m; i++)
{
int u, v, w;
cin >> u >> v >> w;
e[i].u = u;
e[i].v = v;
e[i].dis = w;
}
for(int i = 1; i <= 2 * n; i++)
{
lg[i] = lg[i - 1] + ((1 << lg[i - 1]) == i);
}
Kruskal();
for(int i = 1; i < 2 * n; i++)
{
if(father[i] == i)
{
dfs(i, 0);
}
}
while(q--)
{
int x, y;
cin >> x >> y;
cout << lca(x, y) << endl;
}
return 0;
}
标签:std,yi,int,father,稳定性,蓝桥,fa,2023,省赛
From: https://blog.csdn.net/hehe_666888/article/details/142712717