蓝桥杯2023年第十四届省赛A组-网络稳定性

题目描述

有一个局域网,由 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值