欢迎光临散文网 会员登陆 & 注册

【ROSALIND】【练Python,学生信】32 构建一棵树

2020-01-22 17:58 作者:未琢  | 我要投稿

如果第一次阅读本系列文档请先移步阅读【ROSALIND】【练Python,学生信】00 写在前面  谢谢配合~

题目:

构建一棵树(Completing a Tree)

Given: A positive integer n (n≤1000) and an adjacency list corresponding to a graph on n nodes that contains no cycles.

所给:一个不大于1000的正整数n以及一个邻接表,对应一个有n个结点且无环的图。

Return: The minimum number of edges that can be added to the graph to produce a tree.

需得:添加到图中从而构成树的边的最小数目。

 

测试数据

10

1 2

2 8

4 10

5 9

6 10

7 9

测试输出

3

 

生物学背景

        进化树是进化生物学中用来表示物种进化关系的图表。从进化树中我们可以读出物种间的进化关系和距离。

 

数学背景

        所谓无向图就是边没有方向,相连两个点可以互相抵达的图。树则是不含环的无向图,结构与自然界中的相对应,如下所示:

        无向图顶点的边数称为度(degree),度为1的结点为叶子结点,度大于1的结点为内节点。

        邻接表是数组与链表相结合的存储方法。本题中所给的邻接表每行给出的两个数字代表两个结点由边相连。

 

思路

        由给出的示例数据可以画出下图:

        从绘图结果很容易看出,这十个结点形成了四“堆”:



只需要添加三条边就可以变成一棵树。

        示例所给的数据比较简单,但对复杂数据,原理是相同的,请详见代码注释。


代码

f = open('input.txt', 'r')
lines = f.readlines()
f.close()

num = lines[
0] # 存储结点的数目
edges = lines[1:] # 存储边的关系
i = 1
nodes = []
while i <= int(num):
    nodes.append(
str(i)) # 用一个列表保存所有节点
   
i += 1

fedge = edges[0].replace('\n','') # 把邻接表第一行取出来,作为第一“堆”的基础
fedge = fedge.split(' ')
nodes.remove(fedge[
0])
nodes.remove(fedge[
1])
tree = [fedge]
# tree用来存储结点通过邻接表存储的关系形成的“堆”
flag = 1 # flag存储现在tree里有几“堆”
i = 1
while i < len(edges): # i遍历邻接表
   
edge = edges[i].replace('\n','')
    edge = edge.split(
' ')
   
if edge[0] in nodes:
        nodes.remove(edge[
0]) # 每取出一个边,就把形成边的结点从结点列表中删去
   
if edge[1] in nodes:
        nodes.remove(edge[
1])
    j =
0
   
tag = 0
   
note = []
   
while j < flag: # j用来遍历各“堆”
       
if edge[0] in tree[j]: # 如果这条边的一个结点已经在其中一个“堆”里
           
tree[j].append(edge[1]) # 把这个边加入这一“堆”
           
tag += 1
           
note.append(j) # note存储这个结点在哪个“堆”
           
j += 1
       
elif edge[1] in tree[j]:
            tree[j].append(edge[
0])
            tag +=
1
           
note.append(j)
            j +=
1
       
else: # 如果不在这一“堆”里,j加一,以查找下一“堆”
           
j += 1
   
if tag == 0: # 如果在之前存在的“堆”里都没有这条边
       
tree.append(edge)
        flag +=
1 # 添加一个新的“堆”
   
if tag == 2: # 如果两个结点各在两“堆”中,说明这两个“堆”可以合并
       
flag -= 1
       
tree[note[0]].extend(tree[note[1]])
        tree.remove(tree[note[
1]]) # 合并两“堆”并删去其中一个
       
tree[note[0]].remove(edge[0])
        tree[note[
0]].remove(edge[1]) # 删去由合并导致的重复结点

   
i += 1

print(tree)
lennodes =
len(nodes) # 记录现在结点列表中还有几个结点,每个都相当于一个单独的“堆”
sum = (flag - 1) + lennodes # “堆”的数量减去一即为需要添加的边的数量
print(sum)

 




【ROSALIND】【练Python,学生信】32 构建一棵树的评论 (共 条)

分享到微博请遵守国家法律