📜  最小割的 Karger 算法 |第 1 套(介绍和实施)(1)

📅  最后修改于: 2023-12-03 14:55:20.291000             🧑  作者: Mango

最小割的 Karger 算法 |第1套(介绍和实现)

算法介绍

最小割的 Karger 算法是一种解决图论问题的随机化算法。该算法的基本思想是将一个图不断地缩小,直到只有两个节点为止,这两个节点之间连接的边所代表的权值就是该图的最小割。

具体操作步骤如下:

  1. 从原图中随机选择一条边;
  2. 将该边两端的节点合并为一个节点,同时合并它们之间的边;
  3. 删除原图中所有连接此边两端节点的边;
  4. 重复步骤 1~3,直到只剩下两个节点为止;
  5. 计算这两个节点之间连接的边所代表的权值,即为原图的最小割。

Karger 算法最好的情况下可以在 $O(n^2 \log n)$ 的时间内求解最小割,但是在实际应用中通常需要进行多次随机化求解以降低出错的概率,因此其时间复杂度通常被认为是 $O(n^4)$。然而,Karger 算法具有良好的随机性和实用性,被广泛应用于求解各种图论问题中。

代码实现

Karger 算法的简单实现代码如下(Python 语言):

import random

def kargerMinCut(adj):
    n = len(adj)
    contract = [i for i in range(n)]
    while n > 2:
        s, t = random.sample(range(n), 2)
        adj[contract[s]] += adj[contract[t]]
        for i in range(n):
            for j in range(len(adj[i])):
                if adj[i][j] == contract[t]:
                    adj[i][j] = contract[s]
        while contract[t] < n - 1:
            contract[contract[t]] = contract[t + 1]
            t += 1
        n -= 1
        
    minCut = len(adj[contract[0]])
    return minCut

该实现采用邻接表表示图,随机选取一条边对图进行缩小,并更新边表,直到只剩下两个节点。将剩余两个节点之间连接的边所代表的权值作为最小割。

具体使用可以参考下面的代码片段:

# 构造邻接表(即边表)
adj = [[] for i in range(6)]
adj[0] = [1, 2]
adj[1] = [0, 2, 3]
adj[2] = [0, 1, 3, 4]
adj[3] = [1, 2, 4, 5]
adj[4] = [2, 3, 5]
adj[5] = [3, 4]

# 求最小割
for i in range(40):
    minCut = kargerMinCut(adj)
    print(minCut)

该代码构造了一个6个节点的图,并随机求出了40次的最小割。可以看到,每次求解得出的最小割不一定相同,因此需要进行多次随机求解才能保证得到较为准确的结果。

参考资料
  • Karger, R. (1993). Global minimum cuts in RNC, and other ramifications of a simple min cut algorithm. Proceedings of the twenty-fifth annual ACM symposium on Theory of computing, 50-49.

  • 《算法导论(第三版)》,作者:Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein,中国工信出版集团,2016年。