试题编号: | 201812-4 |
试题名称: | 数据中心 |
时间限制: | 1.0s |
内存限制: | 512.0MB |
问题描述: | 样例输入 4 样例输出 4 样例说明 下图是样例说明。 |
问题链接:CCF201812-4 数据中心
问题分析
根据这个题提供的图片说明,很容易看出这是一道求最小生成树(n个点,只存在n-1条边,且边权重之和最小。对应样例就是4个节点,3条边,通过样例说明可以看出来)中最大边权(n-1个节点中最大的那个边的权重,对应题目中就是最大传输时间)的题目。不了解最小生成树的同学可以百度查一下再回来看本题解。
首先,一看到题目是最小生成树,相信会的同学看了就会很开心,然后就开始用邻接矩阵或者邻接表去存储图,之后用普利姆算法或者克鲁斯卡尔算法去求最小生成树,但是这样做的结果很可能是...
两种算法去做都是超时,并且空间占用也很大。所以我们需要采用一种又省时间又省空间的方法去处理最小生成树,所以我们本题用并查集去做,对于不知道并查集是什么的同学,可以自行百度一下。我之后有时间了也会去写一篇并查集处理怎么处理最小生成树的文章。这样处理,就会得到下面的结果:
具体实现请看下面代码
满分程序
#克鲁斯卡尔算法,采用并查集存储数据
def kru(tree,m,n):
#union为并查集,并设初值为-1
union=[i for i in range(m)]
#首先按照权值大小由小到大对tree排序
tree.sort(key=lambda x:x[2])
#先将权值最小的加入到并查集中去
union[tree[0][0]]=tree[0][1]
length=len(tree)
max_leaf=-1
for i in range(1,length):
#首先找到两个节点的根在哪里
posi_i=tree[i][0]
posi_j=tree[i][1]
while(union[posi_i]!=posi_i):
posi_i=union[posi_i]
while(union[posi_j]!=posi_j):
posi_j=union[posi_j]
#如果两节点根相同,代表形成了回路。故不选择这两个节点
if posi_i==posi_j:
continue
#按照节点大小来排序,这样不会出现冲突(所有的点的顺序都是一个方向的)
elif posi_i>posi_j:
union[posi_j]=posi_i
else :
union[posi_i]=posi_j
if tree[i][2]>max_leaf:
max_leaf=tree[i][2]
#如果union的长度等于n-1,代表最小生成树已经构建完成了。
if len(union)==n-1:
return max_leaf
return max_leaf
#主函数
n=int(input())
m=int(input())
root=int(input())-1
#创建一个m行,3列的数组,并且初值全部为0
tree=[[0 for i in range(3)]for j in range(m)]
#读入信息,存入到tree中去
for i in range(m):
inpu=input().split()
for j in range(3):
tree[i][j]=int(inpu[j])
if n==0:
print(0)
else:
print(kru(tree,max(m+1,n+1),n))