局域网
题目背景
某个局域网内有 n n n 台计算机,由于搭建局域网时工作人员的疏忽,现在局域网内的连接形成了回路,我们知道如果局域网形成回路那么数据将不停的在回路内传输,造成网络卡的现象。因为连接计算机的网线本身不同,所以有一些连线不是很畅通,我们用 f ( i , j ) f(i,j) f(i,j) 表示 i , j i,j i,j 之间连接的畅通程度, f ( i , j ) f(i,j) f(i,j) 值越小表示 i , j i,j i,j 之间连接越通畅, f ( i , j ) f(i,j) f(i,j) 为 0 0 0 表示 i , j i,j i,j 之间无网线连接。
题目描述
现在需要解决回路问题,我们将除去一些连线,使得网络中没有回路,不改变原图节点的连通性,并且被除去网线的 ∑ f ( i , j ) \sum f(i,j) ∑f(i,j) 最大,请求出这个最大值。
输入格式
第一行两个正整数 n , k n,k n,k。
接下来的 k k k 行每行三个正整数 i , j , m i,j,m i,j,m 表示 i , j i,j i,j 两台计算机之间有网线联通,通畅程度为 m m m。
输出格式
一个正整数, ∑ f ( i , j ) \sum f(i,j) ∑f(i,j) 的最大值。
样例 #1
样例输入 #1
5 5
1 2 8
1 3 1
1 5 3
2 4 5
3 4 2
样例输出 #1
8
提示
对于全部数据,保证 1 ≤ n ≤ 100 1\le n \le 100 1≤n≤100, 1 ≤ f ( i , j ) ≤ 1000 1\le f(i,j)\le 1000 1≤f(i,j)≤1000。
题解
首先明确一些信息:
- 这是一个无向图(我一开始当成有向图来做了)
- 这题是一个求最小生成树的题目
- 这题的目标不是求最小生成树,而是最小生成树的总权值(尽管它说的是删除掉的边的权值和,但是求出最小生成树的权值,删除掉的也就出来了)
- 这题有可能有多个连通分量,每个连通分量的最小生成树的总权值都要求一次
最小生成树算法主要有以下几种:
无权图(权值全一样的图):BFS、Prim、Kruskal
有权图:Prim、Kruskal
其中Kruskal算法涉及并查集数据结构,我不太懂并查集实现,所以这道题我就使用了Prim算法,因为不需要我们真的去还原最小生成树,当然,想还原也不难。
既然不需要还原,我们只需要知道,Prim算法每次从优先队列中取出一条边,这条边指向的节点只要没被访问过,那么我们就可以把这条边的权值加在最小生成树的总权值中。
代码:
注意一些地方,因为Python的heapq不能指定对元组的第几位进行排序,只能针对元组的第一位进行堆排序,所以我这里设计的图会有点怪。
import heapq
import copy
def myPrim(graph, startnode):
global N, K, ans, visited
if visited[startnode] == 1:
return
visited[startnode] = 1
priority_queue = copy.deepcopy(graph[startnode])
heapq.heapify(priority_queue)
while priority_queue:
node = heapq.heappop(priority_queue)
if visited[node[1]] == 0:
ans += node[0]
visited[node[1]] = 1
else:
continue
for neighbor in graph[node[1]]:
if visited[neighbor[1]] != 1:
heapq.heappush(priority_queue, neighbor)
N, K = map(int, input().strip().split())
graph = {i+1: [] for i in range(N)}
totalweight, ans = 0, 0
for i in range(K):
val = list(map(int, input().strip().split()))
graph[val[0]].append((val[2], val[1], val[0]))
graph[val[1]].append((val[2], val[0], val[1]))
totalweight += val[2]
visited = [0 for _ in range(N+1)]
for i in range(1, N+1):
myPrim(graph, i)
print(totalweight-ans)