蓝桥杯 网络稳定性

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

解题

最开始我是想用dfs直接写因为他给了起点和终点代码如下

#include<iostream>
#include<vector>
#include<map>
#include<cstring>
#define endl '\n'
#define int long long
using namespace std;
map<int,map<int, int>>arr;
int ans = 0;
int cnt = 0x3f3f3f3f;
int st[50000]={0};
int is[50000] = { 0 };
void dfs(int u, int v,int x)//u为当前的点,u为父节点,v为目标节点
{
	if (u == v)
	{
		ans = max(ans, cnt);
		return;
	}
	for (auto tmp:arr[u])
	{
		if (st[tmp.first]!=1)
		{
			st[tmp.first] = 1;
			cnt = min(cnt, tmp.second);
			dfs(tmp.first, v, u);
		}
		else
			continue;
	}
	return;
}
void solve()
{
    int n, m, s;
    cin >> n >> m >> s;

    for (int i = 0; i < m; i++)
    {
        int a, b, c;
        cin >> a >> b >> c;
        arr[a][b] = c;
        arr[b][a] = c;
        is[a] = is[b] = 1;
    }

    for (int i = 0; i < s; i++)
    {
        int a, b;
        cin >> a >> b;
        st[a] = 1;
        dfs(a, b, a);
        if (st[b]==0||is[b]==0)
            cout << -1 << endl;
        else
        {
            cout << ans << endl;
        }
        ans = 0;
        cnt = 0x3f3f3f3f;
        memset(st, 0, sizeof(st));
    }

}

signed main()
{
	ios::sync_with_stdio;
	cin.tie(0);
	cout.tie(0);
	int t = 1;
	while (t--)
		solve();
	return 0;
}

但这样写只得了5分难绷。然后我想到了kruskal 重构树和LCA重新写终于对了下面是正解

#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#define int long long
#define endl '\n'
using namespace std;
const int N = 4e5 + 10, K = 20, M = 3e5 + 10;
int par[N], a[N], f[N][K], dep[N], n, m, q,u,v;
bool vis[N];
vector<int>E[N];
struct node
{
	int u, v, w;
}e[M];
int find(int x)
{
	return par[x] == x ? x :par[x]=find(par[x]);//查找节点x的根节点也就是找到一个节点他的这个连通分量的根节点是他自己
}
bool cmp(node a, node b)
{
	return a.w > b.w;
}
void dfs(int u, int fa)
{
	vis[u] = true;
	dep[u] = dep[fa] + 1;
	f[u][0] = fa;
	for (auto tmp : E[u])
	{
		if (tmp!=fa)
			dfs(tmp, u);
	}
}
int lca(int u, int v)
{
	if (dep[u] < dep[v])
		swap(u, v);
	int d = dep[u] - dep[v];
	for (int i = K - 1; i >= 0; i--)
	{
		if ((d >> i) & 1)
		{
			u = f[u][i];
		}
	}//将u,v调整至同一深度
	if (u == v)
		return u;
	for (int i = K - 1; i >= 0; i--)
	{
		if (f[u][i] != f[v][i])
			u = f[u][i], v = f[v][i];   //看上面的每一层节点是否相同,因为是从最高开始看起,所以只要出现这一层两个点的祖先不一样,那这一层的上一层就一定是最近公共祖先
	}
	return f[u][0];//返回共同节点的父节点
}
void solve()
{
	cin >> n >> m>>q;
	for (int i = 1; i <= n+m; i++)
		par[i] = i;
	for (int i = 1; i <= m; i++)
		cin >> e[i].u >> e[i].v >> e[i].w;
	sort(e + 1, e + m + 1, cmp);
	int cnt = n;
	for (int i = 1; i <= m; i++)
	{
		int u = e[i].u;
		int v = e[i].v;
		int w = e[i].w;
		u = find(u), v = find(v);
		if (u == v)
			continue;
		++cnt;
		par[u] = par[v] = cnt;
		E[cnt].push_back(u);
		E[cnt].push_back(v);
		a[cnt] = w;
	}//捏造一个节点将两个节点连接起来方便find()操作。
	for (int i = cnt; i >= 1; i--)
	{
		if (!vis[i])
			dfs(i, 0);//最初将每一个节点的父节点设置为0
	}
	for (int j = 1; j < K; j++)
		for (int i = 1; i <= cnt; i++)
			f[i][j] = f[f[i][j - 1]][j - 1];//从底层开始一层一层向上更新
	while (q--)
	{
		cin >> u >> v;
		if (find(u) != find(v))
		{
			cout << -1 << endl;
			continue;
		}
		else
		{
			cout << a[lca(u,v)] << endl;
		}
	}

}
signed main()
{
	ios::sync_with_stdio;
	cin.tie(0);
	cout.tie(0);
	int t = 1;
	while (t--)
		solve();
	return 0;
}

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值