二分图判别算法

下面的表述主要以严谨的图论表述为主:

将阐述以下三点:

  • 二分图的定义
  • 标记法判别连通图
  • 染色法-二分图判别算法(使用深度优先算法 DFS)

一、二分图定义

二分图是图论中的一种特殊模型:

若能将无向图 G=(V,E) 的顶点 V 划分为两个交集为空的顶点集,并且任意边的两个端点都分属于两个集合,则称图 G 为一个为二分图

也就是说:它可以被划分为两个部分,每个部分内的点互不相连

image

二、标记法判别连通图

这里补充一个连通图的判别方法,或者说是判断一个图 G=(V,E)能够划分为连通图的最少数量

  • 给定一个有 V 个顶点的图(邻接矩阵)
  • int k=1
  • A 操作={任取一个点标记为 k,将所有与标记 k 相连的点都标记为 k,直到检查到与 k 相连的点都标记为 k,记录已经标记的点总数 X}
  • if(X==V) return k
  • else k=k+1 重复 A 操作
def dfs(graph, visited, v):  
    visited[v] = True  
    count = 1  # 计数当前连通分量的点数  
    for i in range(len(graph)):  
        if graph[v][i] == 1 and not visited[i]:  
            count += dfs(graph, visited, i)  # 递归DFS,计数  
    return count  
def find_k(graph):  
    V = len(graph)  
    k = 1  
    while k <= V: 
        visited = [False] * V 
        total_count = 0  
        for v in range(V):  # 遍历每个顶点  
            if not visited[v]:  
                count = dfs(graph, visited, v)  # 深度优先遍历,计数  
                total_count += count  
        if total_count == V: 
            return k 
        k += 1   
# 示例  
graph = [  
    [0, 1, 0, 0],  
    [1, 0, 1, 1],  
    [0, 1, 0, 0],  
    [0, 1, 0, 0]  
]  
result = find_k(graph)  
print(result) 

判别连通图的方法下面判别二分图需要用到

三、染色法判别二分图

我们想象二分图也就是把一个图划分,划分内部不相连,也就是我们可以把相连表示仇视关系,利用敌人的敌人是朋友的思想,我就产生了递归染色法的想法:

  • 设置一个起始点染色为红色,相连的均染为蓝色,连接蓝色的点检查是否染色,如果没有染色则染为红色,以此遍历整个**连通图,直到染色点数==连通图点数 V_i
  • 我们注意到这只能在连通图内进行,所以我们才要用上面引出连通图的算法,所以我们应该在第 1 块、第 2 块……第 k 块都设置一个起始点,这样就可以保证染色到整个图
  • 最后,我们检查每一条边是否出现连接的点是同色,如果存在则该图不是二分图,反之成立

Code-hxw

def dfs_connected(graph, visited, v):  
    visited[v] = True  
    for i in range(len(graph)):  
        if graph[v][i] == 1 and not visited[i]:  # 如果有边且未访问  
            dfs_connected(graph, visited, i)  
def count_connected_components(graph):  
    V = len(graph)  
    visited = [False] * V  
    count = 0  
    for v in range(V):  
        if not visited[v]:  # 若未访问,意味着找到一个新连通分量  
            dfs_connected(graph, visited, v)  
            count += 1  
    return count  
def is_bipartite_with_groups(graph):  
    V = len(graph)  
    color = [-1] * V  # -1 表示未染色  
    groups = {0: [], 1: []}  # 用于存储两个组的顶点  
    def dfs_bipartite(v, c):  
        color[v] = c  
        groups[c].append(v)  # 将顶点添加到相应的组  
        for i in range(V):  
            if graph[v][i] == 1:  # 检查相连的边  
                if color[i] == -1:  # 若未染色  
                    if not dfs_bipartite(i, 1 - c):  # 递归染色(反色)  
                        return False  
                elif color[i] == c:  
                    return False  
        return True  
    for start in range(V):  
        if color[start] == -1:  # 若未染色,开始染色  
            groups = {0: [], 1: []}  
            if not dfs_bipartite(start, 0):  
                return False, {}  
    return True, groups  
# 示例邻接矩阵  
graph = [  
    [0, 1, 0, 0, 1],  
    [1, 0, 1, 0, 0],  
    [0, 1, 0, 1, 0],  
    [0, 0, 1, 0, 1],  
    [1, 0, 0, 1, 0]  
] 
connected_components = count_connected_components(graph)  
print(f"Connected components: {connected_components}")  
is_bipartite_graph, bipartite_groups = is_bipartite_with_groups(graph)  
if is_bipartite_graph:  
    print("True")  
    print(f"Bipartite groups: {bipartite_groups[0]} and {bipartite_groups[1]}")  
else:  
    print("False")

  • 算法
    428 引用 • 254 回帖 • 24 关注
1 操作
XiaoweiH 在 2024-10-10 00:26:41 更新了该帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...