栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

【python-NOJ-44】【001】—第五季【类】—朋友圈(并查集)

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【python-NOJ-44】【001】—第五季【类】—朋友圈(并查集)

题目描述:

 解析:

这个问题抽象为求一个图的连通子图的个数。可以采用DFS遍历,求出连通度;或者采用并查集。

此题使用使用并查集。

(1)初始化:将每个节点的父节点初始化为自己,此时n个节点有n个朋友圈;

(2)第一步:根据输入的序列,将node数组和对应的father数组进行第二波初始化,注意father[tail]=head,这样才能成功的从后往前寻找时停止;

(3)第三步:遍历。对于node中的每个节点,查找其父节点,如果此节点等于其父节点,即father[node]=node,说明已经找到祖先节点,则停止对该节点的查找,跳入下一个节点。反之说明还没有找到其祖先节点,那么使当前节点的父节点等于其父节点的父节点,然后再比较更新过后,这个节点的父节点跟父节点的父节点进行比较,直到相同。

(4)最后,整理为字典得到朋友圈个数。

知识点:

(1)enumerate()函数

——语法:enumerate(sequence, [start=0])

——参数:sequence是一个序列,迭代器或者其他迭代对象;start下标起始位置;

——返回值:返回enumerate枚举对象;

>>>seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1))       # 下标从 1 开始
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]

(2)并查集

了解并查集的思想和基本操作方式:即一直更新一个节点,第一次是它本身的父节点,第二次它的父节点变为它父节点的父节点,即爷节点。再比较它此时的父节点(也就是爷节点)是否跟爷节点(即太爷节点)相同,相同则break停止对该节点的寻找,不相同再更新其父节点为太爷节点。然后一直如此。

核心代码如下:

for node in nodes:
    while True:
        # 对于每个节点,找它的父节点,看他的父节点的父节点是谁,直到找到父节点跟节点相同,说明到头
        father_of_node=father[node]
        if father_of_node!=father[father_of_node]:
            father[node]=father[father_of_node]
        else:
            break
代码:
n=int(input())
nodes=list(range(n))
father=list(range(n))

m=int(input())
edges=[]
for i in range(m):
    edge=[int(i) for i in input().split(' ')]
    edges.append(edge)
for edge in edges:
    head=edge[0]
    tail=edge[1]
    father[tail]=head
for node in nodes:
    while True:
        # 对于每个节点,找它的父节点,看他的父节点的父节点是谁,直到找到父节点跟节点相同,说明到头
        father_of_node=father[node]
        if father_of_node!=father[father_of_node]:
            father[node]=father[father_of_node]
        else:
            break
dic={}
for i,f in enumerate(father):
    dic[f]=[]
print(len(dic))
延展知识:

此题还可以使用DFS遍历得到。

(1)原理:对于每个节点,对其执行一遍DFS后,会找到与之相连的所有节点,并将它标记。所以,执行了多少遍DFS,就有多少个连通子图;

(2)实现方法:刚开始每个节点都没走过。对于每个节点,判断其是否走过,即used[i]==1,没有则对齐实行DFS,同时k++,标记实行了几次DFS。对于每次DFS而言,其都通过不断调用自身,找到了与自己相连的所有节点。

基本代码如下:

n=int(input())
dis=[[0 for i in range(n)]for j in range(n)]
used=[0 for i in range(n)]
m=int(input())
for i in range(m):
    a=[int(i) for i in input().split(' ')]
    dis[a[0]][a[1]]=1
    dis[a[1]][a[0]]=1

def DFS(i,n):
    used[i]=1
    for j in range(n):
        if dis[i][j]==1:
            if used[j]!=1:
                DFS(j,n)
k=0
for i in range(n):
    if used[i]==0:
        k+=1
        DFS(i,n)
print(k)
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/445561.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号