Генерация случайного кубического графа с равномерной вероятностью (или меньше) - PullRequest
9 голосов
/ 24 июня 2010

Хотя это может выглядеть как домашняя работа, уверяю вас, это не так.Это связано с некоторым домашним заданием, которое я сделал.

Давайте назовем неориентированный граф без самоограничений "кубическим", если каждая вершина имеет степень ровно три.Учитывая положительное целое число N, я хотел бы генерировать случайный кубический граф на N вершинах.Я бы хотел, чтобы он имел одинаковую вероятность, то есть, если на N вершинах имеется M кубических графов, вероятность генерации каждого равна 1 / M.Более слабое условие, которое все еще в порядке, состоит в том, что каждый кубический граф имеет ненулевую вероятность.

Я чувствую есть быстрый и умный способ сделать это, но до сих пор я был неудачным.

Я плохой кодер, пожалуйста, потерпите этот ужасный код:

PRE :dge = (3 * узлов) / 2, узлы четные, константы выбираются таким образомчто хеш работает (BIG_PRIME больше ребер, SMALL_PRIME больше узлов, LOAD_FACTOR мал).

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 ]

10 голосов
/ 24 июня 2010

Предположим, что N чётно. (В противном случае не может быть кубического графа на N вершинах).

Вы можете сделать следующее:

Возьмите 3N баллов и разделите их на N групп по 3 балла в каждой.

Теперь попарно разбейте эти 3N точек (примечание: 3N четное). то есть случайно жениться на двух точках и заключить 3N / 2 брака).

Если есть спаривание между группой i и группой j, создайте ребро между i и j. Это дает график на N вершин.

Если это случайное спаривание не создает несколько ребер или петель, у вас есть кубический граф.

Если нет, попробуйте еще раз. Это выполняется в ожидаемое линейное время и генерирует равномерное распределение.

Примечание: все кубические графы на N вершинах генерируются этим методом (в ответ на комментарии Хэмиша).

Чтобы увидеть это:

Пусть 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).

Таким образом, любому кубическому графу соответствует спаривание, и наоборот ...

Более подробную информацию об этом алгоритме и более быстрых алгоритмах можно найти здесь: Быстрая генерация случайных регулярных графов .

2 голосов
/ 25 июня 2010

Предупреждение: в этом ответе я делаю много интуитивных, но, возможно, неправильных утверждений.Вы обязательно должны их доказать, если собираетесь использовать эту идею.

Перечисление кубических графов

При работе со случайным выбором хорошей отправной точкой является выяснение того, какперечислить все ваши возможные элементы.Это может раскрыть некоторые структуры и привести вас к алгоритму.

Вот моя стратегия перечисления кубических графов: выберите первую вершину и выполните итерации по всем возможным вариантам выбора трех смежных вершин.Во время этих итераций выполните возврат к следующей вершине с предупреждением о том, сколько ребер необходимо для того, чтобы каждая степень вершины достигла 3. Продолжайте таким образом, пока не будет достигнут самый низкий уровень.Теперь у вас есть ваш первый кубический граф.Отмените недавно добавленные ребра и переходите к следующей возможности, пока не останется ни одного.Есть несколько деталей реализации, которые вам нужно рассмотреть, но, как правило, это просто.

Обобщение перечисления в выбор

Как только вы можете перечислить все элементы, это тривиальносделать случайный выбор.Например, вы можете отсканировать список один раз, чтобы вычислить его размер, затем выбрать случайное число в [0, размер), а затем снова просканировать последовательность, чтобы получить элемент с этим смещением.Это невероятно неэффективно, принимая как минимум время, пропорциональное числу кубических графов O (n ^ 3), но это работает.

Равномерная вероятность жертвенности для эффективности

Очевидное ускорение здесь состоит в том, чтобы делать случайные выборы ребер на каждом уровне, вместо того, чтобы повторять каждую возможность.К сожалению, это будет благоприятствовать некоторым графикам из-за того, как ваши ранние выборы влияют на доступность более поздних выборов.Принимая во внимание необходимость отслеживать оставшиеся свободные вершины, вы должны быть в состоянии достичь O (n log n) времени и O (n) пространства.Значительно лучше, чем алгоритм перечисления.

...

Вероятно, можно сделать лучше.Наверное, намного лучше.Но это должно помочь вам начать.

1 голос
/ 25 июня 2010

Другой термин для кубического графика - это 3- регулярный граф или трехвалентный граф .

Ваша проблема нуждается в небольшом дополнительном разъяснении, потому что «количество кубических графов» может означать количество кубических графов в 2 n узлах, которые не изоморфны друг другу, или число (не изоморфные) кубические графы на 2 n помеченных узлах. Первый из них задается целочисленной последовательностью A005638 , и, скорее всего, нетривиальной задачей является равномерный выбор класса случайных изоморфизмов кубических графов (то есть не перечисление их всех, а затем выбор одного класса). Последний задается как A002829 .

В Википедии есть статья о случайных регулярных графах , на которую стоит взглянуть.

...