问题:关节点和重连通分量
题目描述
假若在删去顶点v以及和v相关联的各边之后,将图的一个连通分量分割成两个或两个以上的连接分量,则称顶点v为该图的一个关节点。一个没有关节点的连通图称为重连通图。在重连通图上,任意一对顶点之间至少存在两条路径,则在删去某个顶点以及依附于该顶点的各边时也不会破坏图的连通性。
利用深度优先搜索可以求出图的关节点,并由此可以判断图是否是重连通的。
通过修改深度优先搜索遍历的算法便可以得到求关节点的算法,其算法描述如下:
在本题中,读入一个无向图的邻接矩阵(即数组表示),建立无向图并按照以上描述中的算法求出所有的关节点,并输出这些关节点。
输入 :
输入的第一行包含一个正整数n,表示图中共有n个顶点。其中n不超过50。
以后的n行中每行有n个用空格隔开的整数0或1,对于第i行的第j个整数,如果为1,则表示第i个顶点和第j个顶点有直接连接,0表示没有直接连接。当i和j相等的时候,保证对应的整数为0。
输入保证邻接矩阵为对称矩阵,即输入的图一定是无向图,且保证图中只有一个连通分量。
输出:
第一行有一个整数x,即图中关节点的个数。
第二行输出x个整数,表示所有关节点的顶点编号,请按照编号从小到大的顺序输出。每个整数后输出一个空格,并请注意行尾输出换行。
样例输入
4
01 1 1
1 0 0 0
1 0 0 0
1 0 0 0
样例输出
1
0
提示
在本题中,需要掌握图的深度优先遍历的方法,并需要掌握通过深度优先搜索求得图中关节点的算法。通过生成深度优先生成树可以得出两类关节点的特性:
-
若生成树的根有两棵或两棵以上的子树,则此根顶点必为关节点。
-
若生成树中某个非叶子顶点v,其某棵子树的根和子树中的其他结点均没有指向v的祖先的回边,则说明v是关节点。
注意以上两点特性,就可以成功的通过深度优先搜索遍历的算法得出图中的关节点了。
代码展示:
n = int(input())
visited=[0]*n#访问列表,用于判断节点访问状态
low=[1000000]*n#初始化权值列表
count=0
end_ans=[]#结果列表
def DFS(G,v0):
global count,visited,low,n,end_ans
count+=1
visited[v0]=min=count
for i in range(0,n):
if G[v0][i]!=0:#读入邻接节点
if visited[i]==0:
DFS(G,i)
if low[i]<min:
min=low[i]
if low[i]>=visited[v0]:
end_ans.append(v0)
else:
if visited[i]<min:
min=visited[i]
low[v0]=min
def FindArticul(G):
global visited,count,n,end_ans
visited[0]=1
count=1
for i in range(1,n):
if G[0][i]!=0:
DFS(G,i)
if count<n:
end_ans.append(0)
while i<n:
if G[0][i]!=0 and visited[i]==0:
DFS(G,i)
i+=1
return
if __name__=='__main__':
G=[]#无向连通图-邻接矩阵形式
for i in range(0, n):
res = input()
ans = res.split(' ')
G.append([int(i) for i in ans])
FindArticul(G)
print(len(end_ans))
end_ans.sort()
for i in end_ans:
print(i,end=' ')
print()