生成具有均匀概率(或更小)的随机三次图

时间:2010-06-24 18:24:12

标签: c algorithm graph graph-theory random

虽然这可能看起来像家庭作业,但我向你保证不是。这源于我做过的一些家庭作业。

如果每个顶点的度数恰好为3,那么让我们调用一个没有自我边缘“立方”的无向图。给定正整数N我想在N个顶点上生成随机立方图。我希望它具有统一的概率,也就是说,如果N个顶点上有M个立方图,则生成每个顶点的概率为1 / M.一个较弱的条件仍然很好,每个立方图都有非零概率。

感觉有一种快速而聪明的方法可以做到这一点,但到目前为止,我一直没有成功。

我是一个糟糕的程序员,请忍受这个糟糕的代码:

PRE:edges =(3 *个节点)/ 2,节点是偶数,选择的常数是哈希工作的方式(BIG_PRIME大于边缘,SMALL_PRIME大于节点,LOAD_FACTOR很小)。 / p>

void random_cubic_graph() {

int i, j, k, count;
int *degree;
char guard;

count = 0;
degree = (int*) calloc(nodes, sizeof(int));

while (count < edges) {

    /* Try a new edge at random */

    guard = 0;
    i = rand() % nodes;
    j = rand() % nodes;

    /* Checks if it is a self-edge */

    if (i == j)
        guard = 1;

    /* Checks that the degrees are 3 or less */

    if (degree[i] > 2 || degree[j] > 2) 
        guard = 1;

    /* Checks that the edge was not already selected with an hash */

    k = 0;
    while(A[(j + k*BIG_PRIME) % (LOAD_FACTOR*edges)] != 0) {
        if (A[(j + k*BIG_PRIME) % (LOAD_FACTOR*edges)] % SMALL_PRIME == j)
            if ((A[(j + k*BIG_PRIME) % (LOAD_FACTOR*edges)] - j) / SMALL_PRIME == i)
                guard = 1;
        k++;
    }

    if (guard == 0)
        A[(j + k*BIG_PRIME) % (LOAD_FACTOR*edges)] = hash(i,j);

    k = 0;
    while(A[(i + k*BIG_PRIME) % (LOAD_FACTOR*edges)] != 0) {
        if (A[(i + k*BIG_PRIME) % (LOAD_FACTOR*edges)] % SMALL_PRIME == i)
            if ((A[(i + k*BIG_PRIME) % (LOAD_FACTOR*edges)] - i) / SMALL_PRIME == j)
                guard = 1;
        k++;
    }

    if (guard == 0) 
        A[(i + k*BIG_PRIME) % (LOAD_FACTOR*edges)] = hash(j,i);

    /* If all checks were passed, increment the count, print the edge, increment the degrees. */

    if (guard == 0) {
        count++;
        printf("%d\t%d\n", i, j);
        degree[i]++;
        degree[j]++;
    }

}

问题是必须选择的最终边缘可能是自我边缘。当N-1个顶点已经是3级时,就会发生这种情况,只有1个具有1级。因此算法可能不会终止。而且,我并不完全相信概率是一致的。

我的代码可能有很多改进,但你能建议一个更好的算法来实现吗?

3 个答案:

答案 0 :(得分:10)

假设N是偶数。 (否则N个顶点上不能有立方图)。

您可以执行以下操作:

取3N分并将它们分成N组,每组3分。

现在随机配对这些3N点(注意:3N是偶数)。即随机结束两点并形成3N / 2婚姻。)

如果组i和组j之间存在配对,则在i和j之间创建一条边。这给出了N个顶点的图形。

如果此随机配对不会创建任何多个边或循环,则您有一个立方图。

如果没有再试一次。这在预期的线性时间内运行并产生均匀分布。

注意:N个顶点上的所有立方图都是通过这种方法生成的(回应Hamish的评论)。

要看到这个:

设G是N个顶点上的立方图。

让顶点为1,2,... N。

让j的三个邻居为A(j),B(j)和C(j)。

对于每个j,构造有序对{(j,A(j)),(j,B(j)),(j,C(j))}的组。

这给了我们3N有序对。我们将它们配对:(u,v)与(v,u)配对。

因此,任何立方图对应配对,反之亦然......

有关此算法和更快算法的更多信息,请访问:Generating Random Regular Graphs Quickly

答案 1 :(得分:2)

警告:我在这个答案中提出了许多直观但可能错误的说法。如果你打算使用这个想法,你一定要证明它们。

枚举立方图

在处理随机选择时,一个好的起点是弄清楚如何枚举所有可能的元素。这可能会揭示一些结构,并引导您进行算法。

这是我枚举立方图的策略:选择第一个顶点,并迭代三个相邻顶点的所有可能选择。在这些迭代期间,递归到下一个顶点,但需要注意每个顶点度数达到3所需的边数。继续以这种方式直到达到最低级别。现在你有了第一个立方图。撤消最近添加的边缘并继续下一个可能性,直到没有剩下。您需要考虑一些实施细节,但通常是直截了当的。

将枚​​举概括为选择

一旦你可以枚举所有元素,做出随机选择是微不足道的。例如,您可以扫描列表一次以计算其大小,然后选择[0,大小]中的随机数,然后再次扫描序列以获取该偏移处的元素。这是非常低效的,在最小时间内与O(n ^ 3)立方图的数量成比例,但它起作用。

牺牲统一的效率概率

这里显而易见的加速是在每个级别进行随机边缘选择,而不是迭代每种可能性。不幸的是,这将有利于某些图表,因为您的早期选择会影响后续选择的可用性。考虑到跟踪剩余自由顶点的需要,您应该能够实现O(n log n)时间和O(n)空间。明显优于枚举算法。

<强> ...

可能做得更好。可能好多了。但这应该让你开始。

答案 2 :(得分:1)

cubic graph 的另一个术语是 3 - regular graph 三价图

你的问题需要更多的澄清,因为“立方图的数量”可能意味着2 n个节点上彼此非同构的立方图的数量或(非)的数量在2 n个标记的节点上的 - 同构的)立方图。前者由整数序列A005638给出,并且有效地均匀地选择立方图的随机同构类(即不将它们全部列出然后选择一个类)可能是一个非平凡的问题。后者由A002829给出。

维基百科上有一篇关于random regular graphs的文章,你应该看一下。