python输出一棵松树_【ROSALIND】【练Python,学生信】32 构建一棵树

题目:

构建一棵树(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 =1nodes = []whilei <=int(num):

nodes.append(str(i))#用一个列表保存所有节点i +=1fedge = edges[0].replace('\n','')#把邻接表第一行取出来,作为第一“堆”的基础fedge = fedge.split(' ')

nodes.remove(fedge[0])

nodes.remove(fedge[1])

tree = [fedge]# tree用来存储结点通过邻接表存储的关系形成的“堆”flag =1# flag存储现在tree里有几“堆”i =1whilei

edge = edge.split(' ')ifedge[0]innodes:

nodes.remove(edge[0])#每取出一个边,就把形成边的结点从结点列表中删去ifedge[1]innodes:

nodes.remove(edge[1])

j =0tag =0note = []whilej < flag:# j用来遍历各“堆”ifedge[0]intree[j]:#如果这条边的一个结点已经在其中一个“堆”里tree[j].append(edge[1])#把这个边加入这一“堆”tag +=1note.append(j)# note存储这个结点在哪个“堆”j +=1elifedge[1]intree[j]:

tree[j].append(edge[0])

tag +=1note.append(j)

j +=1else:#如果不在这一“堆”里,j加一,以查找下一“堆”j +=1iftag ==0:#如果在之前存在的“堆”里都没有这条边tree.append(edge)

flag +=1#添加一个新的“堆”iftag ==2:#如果两个结点各在两“堆”中,说明这两个“堆”可以合并flag -=1tree[note[0]].extend(tree[note[1]])

tree.remove(tree[note[1]])#合并两“堆”并删去其中一个tree[note[0]].remove(edge[0])

tree[note[0]].remove(edge[1])#删去由合并导致的重复结点i +=1print(tree)

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值