在图中查找最小割的随机收缩算法

4

好的,这里是我关于在图形中查找割点的算法(我不是在谈论最小割)的算法:

假设我们有一个非定向图的邻接列表。

  1. 在图上选择任何一个顶点(称为枢轴)
  2. 在图上随机选择另一个顶点(将其表示为 x)
  3. 如果这两个顶点之间有一条边,则从图中删除该边。并将 x 连接到的所有顶点转移到枢轴上。(如果没有,则返回步骤 2。)
  4. 如果其他任何顶点都连接到了 x,则更改邻接列表,使现在 x 被替换为枢轴。也就是说,它们与枢轴相连。
  5. 如果顶点数量大于 2(返回步骤 2)
  6. 如果等于 2。只需计算两个点中任意一个的邻接列表中存在的顶点数。这将给出割。

我的问题是,这个算法正确吗?


它能在几个演示示例中工作吗?如果是这样,那么很可能是的。 - Matt
对不起,您说的“dump all the vertices”是什么意思? - kilotaras
这不是一个适合在 mathematics StackExchange 网站上提问的问题吗? - Geoff
3个回答

1
我只会更改你的随机化。
在选择第一个顶点后,从其邻接列表中选择另一个顶点。现在您可以确定两个顶点之间有边缘。下一步是查找邻接列表中的顶点。

1

这是一个关于无向图的 Krager 最小割算法的很好的解释。

我觉得可能有一个细节你忽略了,或者说我没有看清你的描述。

你需要移除所有自环。

例如,在你移除一个顶点并运行算法之后,顶点 A 可能现在有一条从顶点 A 到顶点 A 的边。这被称为自环。在缩小两个顶点的过程中,它们通常会产生。作为第一步,你可以简单地检查自环是否存在于整个图中,虽然也有一些更复杂的方法。

这样说你明白了吗?


是的,这是Krager的最小割算法。我认为没有生成任何自环。但除此之外,一切似乎都是正确的,对吧? - Ole Gooner
是的,完全正确,除此之外看起来很棒。但要检查自环。例如,当您执行步骤3时,将一个顶点的所有边转储到另一个顶点上。它们之前是连接的,因此在那一点上应该生成至少一个(如果不是多个)“自环”。通常就是这样发生的。无论如何,您可能已经解决了这个问题,我只是想提一下。干得好! - john_science
无论如何,在您运行代码的前两次中检查它们不会有任何损失。以防万一。 - john_science

-1
同意您应该绝对删除自环。另外,我想补充的一点是,在随机选择第一个顶点之后,您不必随机选择另一个节点,直到找到连接到第一个节点的节点,您可以直接从与第一个顶点相连的节点中选择,因为您知道第一个选择的节点连接到多少个节点。所以在更小的范围内进行第二次随机选择。这实际上只是随机选择一条边(由两个节点/顶点确定)。我有一些实现Krager算法的C#代码,您可以尝试一下。它不是最有效的代码(特别是可以使用更有效的数据结构),因为我在200个节点的图上测试了10000次迭代,需要大约30秒才能运行。
using System;
using System.Collections.Generic;
using System.Linq;

namespace MinCut
{
    internal struct Graph
    {
        public int N { get; private set; }
        public readonly List<int> Connections;
        public Graph(int n) : this()
        {
            N = n;
            Connections = new List<int>();
        }

    public override bool Equals(object obj)
    {
        return Equals((Graph)obj);
    }

    public override int GetHashCode()
    {
        return base.GetHashCode();
    }

    private bool Equals(Graph g)
    {
        return N == g.N;
    }
}

internal sealed class GraphContraction
{
    public static void Run(IList<Graph> graphs, int i)
    {
        var liveGraphs = graphs.Count;
        if (i >= liveGraphs)
        {
            throw new Exception("Wrong random index generation; index cannot be larger than the number of nodes");
        }
        var leftV = graphs[i];

        var r = new Random();
        var index = r.Next(0, leftV.Connections.Count);
        var rightV = graphs.Where(x=>x.N == leftV.Connections[index]).Single();

        foreach (var v in graphs.Where(x => !x.Equals(leftV) && x.Connections.Contains(leftV.N))) 
        {
            v.Connections.RemoveAll(x => x == leftV.N);
        }
        foreach (var c in leftV.Connections)
        {
            if (c != rightV.N)
            {
                rightV.Connections.Add(c);
                int c1 = c;
                graphs.Where(x=> x.N == c1).First().Connections.Add(rightV.N);
            }
        }
        graphs.Remove(leftV);
    }
}

}


你(或其他读者)能否展示或链接到“为什么”这种随机化方法是“有效的”?这是一个没有支持的强有力的陈述 - 请分享为什么您确信Pr(整个图上的任何边缘)= 1 / m适用于所有图形。 - newcoder
@newcoder,理论上要获得1/m的概率,您需要运行m^2*log(m)次迭代。这涉及到相当多的数学证明,您可以参考许多在线资源以获得详细的证明,例如http://en.wikipedia.org/wiki/Karger's_algorithm。 - dragonfly02
也许我之前表述不够清晰;我的上一条评论是指选择任何给定边缩小的概率为1/m,其中m是剩余边数。该算法依赖于所有边的概率均匀分布。按照你和@stupi建议的方式选择边实际上并不满足这个要求。 - newcoder
举例来说,考虑以下图形:[(0):1,2,2,3] [(1):0] [(2):0,0] [(3):0] 对于这个图形,m = 4,因此任何宣称选择一条均匀随机边的方法都应计算为Pr(0,1)=1/4,Pr(0,2)=1/4和Pr(0,3)=1/4。 首先均匀随机选择一个顶点,然后从其邻接列表中均匀随机选择一个顶点,我们有Pr(0,1)=5/16,Pr(0,2)=6/16,和Pr(0,3)=5/16。 - newcoder
我不确定您是如何计算出P(0,1) = 5/16,P(0,2) = 6/16和P(0,3) = 5/16的。这是我的计算过程:实际上,P(0,1)是在已经选择了顶点0的情况下随机选择顶点1的条件概率,即P(1|0) = P(0 and 1) / P(0);因为每个选择都是独立的,所以P(0 and 1) = P(0) * P(1),因此P(1|0) = P(1) = 1/4,同样地,P(2|0) = P(2) = 2/4 = 1/2;P(3|0) = 1/4。 - dragonfly02

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接