1141 局域网(kruskal算法)

1. 问题描述:

某个局域网内有 n 台计算机和 k 条双向网线,计算机的编号是 1∼n。由于搭建局域网时工作人员的疏忽,现在局域网内的连接形成了回路,我们知道如果局域网形成回路那么数据将不停的在回路内传输,造成网络卡的现象。注意:对于某一个连接,虽然它是双向的,但我们不将其当做回路。本题中所描述的回路至少要包含两条不同的连接。两台计算机之间最多只会存在一条连接。不存在一条连接,它所连接的两端是同一台计算机。因为连接计算机的网线本身不同,所以有一些连线不是很畅通,我们用 f(i,j) 表示 i,j 之间连接的畅通程度,f(i,j) 值越小表示 i,j 之间连接越通畅。现在我们需要解决回路问题,我们将除去一些连线,使得网络中没有回路且不影响连通性(即如果之前某两个点是连通的,去完之后也必须是连通的),并且被除去网线的 Σf(i,j) 最大,请求出这个最大值。

输入格式

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

输出格式

一个正整数,表示被除去网线的 Σf(i,j) 的最大值。

数据范围

1 ≤ n ≤ 100
0 ≤ k ≤ 200
1 ≤ f(i,j) ≤ 1000

输入样例:

5 5
1 2 8
1 3 1
1 5 3
2 4 5
3 4 2

输出样例:

8
来源:https://www.acwing.com/problem/content/description/1143/

2. 思路分析:

分析题目可以知道边的总和是一定的,要想使得删除的边的权重之和最大,那么应该使得留下的边的权重之和最小,并且删除边之后并不影响连通性,而且因为给出的图并不一定是联通的,所以本质上求解每一个连通块中的最小生成树,也即求解原图中的"最小生成森林",因为题目的输入的是每条边的权重所以使用kruskal算法求解会比较方便一点(prim算法每一次只能求解一个连通块,从连通块的起点向周围扩散所以需要多次调用prim算法,这样就不如kruskal算法方便了),可以发现最终得到的图不一定是联通的,因为每一个连通块都是相互独立的,所以kruskal算法求解每一个连通块的最小生成树的做法是正确的,求解出每一个连通块的中的最小生成树,那么剩余的就是需要删除的边,每一部分相互独立所以最终求解的答案一定是正确的。

3. 代码如下:

from typing import List


class Solution:
    # 并查集查找x的父节点并且进行路径压缩
    def find(self, x: int, fa: List[int]):
        if x != fa[x]: fa[x] = self.find(fa[x], fa)
        return fa[x]

    def process(self):
        n, m = map(int, input().split())
        w = list()
        for i in range(m):
            a, b, c = map(int, input().split())
            # 使用元组来存储边的信息方便后面排序
            w.append((a, b, c))
        # 这道题目是没有重边和自环的, 所以可以直接按照边权从小到大排序
        w.sort(key=lambda x: x[2])
        res = 0
        # 并查集的父节点数组, 因为节点编号是从0开始的但是所以第一个元素也需要占一个坑
        fa = [i for i in range(n + 1)]
        for i in range(m):
            a, b, c = w[i][0], w[i][1], w[i][2]
            t1, t2 = self.find(a, fa), self.find(b, fa)
            if t1 != t2:
                fa[t1] = t2
            # 需要删除当前的边所以需要累加到答案中
            else: res += c
        return res


if __name__ == "__main__":
    print(Solution().process())
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值