【洛谷】P2820 并查集

题目

某个局域网内有 n(n≤100) 台计算机,由于搭建局域网时工作人员的疏忽,现在局域网内的连接形成了回路,我们知道如果局域网形成回路那么数据将不停的在回路内传输,造成网络卡的现象。因为连接计算机的网线本身不同,所以有一些连线不是很畅通,我们用 f(i,j) 表示 i,j 之间连接的畅通程度,f(i,j) 值越小表示 i,j 之间连接越通畅,f(i,j) 为 0 表示 i,j 之间无网线连接。

题目描述

需要解决回路问题,我们将除去一些连线,使得网络中没有回路,并且被除去网线的 ∑f(i,j) 最大,请求出这个最大值。

输入格式

第一行两个正整数 n,k。
接下来的 k 行每行三个正整数 i,j,m 表示 i,j 两台计算机之间有网线联通,通畅程度为 m。

输出格式

一个正整数,∑f(i,j) 的最大值。

解析

根据题目可知,局域网是全部联通的,只是有多余线路导致整个网络形成了回路,要求出被除去网线的 ∑f(i,j),也就是要使用最少的 ∑f(i,j) ,将网络连接起来(把 ∑f(i,j) 看作俩台电脑之间所连网线的长度会好理解一些),所以我可以先把所有电脑网线都拔开,然后使用最短的网线将这些电脑连接起来,剩余的网线长度就是被除去网线长度的最大值。

#include <iostream>
#include <stdio.h>
#include <algorithm>

using namespace std;

int N,K;
// 用来记录输入的结构体
struct cpt{
    int x,y,l;
};
// 100台电脑最大连接数量也就是4950,下标从1开始,所以4951刚刚好
struct cpt c[4951];
// 使用并查集,用来记录每台电脑的上级,下标从1开始
int par[101];
// 并查集find函数,用来寻找某节点的上级
int find1(int x) {
    int r=x;
    // 寻找该节点的上级,直到找到一个节点的上级就是自己退出循环
    while(par[r]!=r){
        r=par[r];
    }
    // 此处 r 表示传入 x 的最上级
    int i=x,j;
    // 压缩路径,将传入 x 的上级设为 r
    while(i!=j){
        j=par[r];
        par[i]=j;
        i=j;
    }
    return r;
}
// 并查集join函数,用来将新的节点加入网络
void join(int x, int y) {
	// 如果上级不一样,修改设置为相同
    int fx=find1(x), fy=find1(y);
    if(fx!=fy){
        par[fx]=fy;
    }
}
// 检查par数组中有几个区块(有几个上级为自己的节点)
int check(){
    int sum = 0;
    for(int i=1; i<=N; i++)
        if(par[i]==i)
            sum ++;
    return sum;
}
// 使用快排的cmp,从小到大
bool cmp(cpt a, cpt b){
    return a.l<b.l;
}

int main(){
	// 用来记录网络中网线的最大长度
    int length=0;
    scanf("%d%d",&N,&K);
    for(int i=1; i<=N; i++)
        par[i]=i;	// 设置每台电脑的上级都为自己
    for(int i=1; i<=K; i++){
        scanf("%d%d%d",&c[i].x,&c[i].y,&c[i].l);
        // 记录网线长度
        length+=c[i].l;
    }
    // 将所有节点之间的连接按照网线长度进行排序
    sort(c+1, c+1+K, cmp);
    // 对所有网线进行循环
    for(int i=1; i<=K; i++){
        int r1 = find1(c[i].x);
        int r2 = find1(c[i].y);
        // 如果这两台电脑的上级不同,则使用网线将这俩个区块连接起来
        // 上级不同说明这两台电脑之间没有连接,此时取出的网线长度还是从小到大排列的
        // 所以使用这个网线连接可以确保使用的是最短的网线
        if(r1 != r2){
            join(c[i].x,c[i].y);
            // 从总长度中减去使用的网线长度
            length-=c[i].l;
        }
    }
    // 剩余的长度即为最大长度
    printf("%d",length);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值