Разработка алгоритма задачи клики

Одно из заданий в моем классе алгоритмов - разработать исчерпывающий алгоритм поиска для решения проблемы клики. То есть, учитывая график размера n, алгоритм должен определить, существует ли полный подграф размера k. Я думаю, что получил ответ, но я не могу не думать, что его можно улучшить. Вот что у меня есть:

Версия 1

input: график, представленный массивом A [0,... n-1], размер k подграфа для поиска.

вывод: True, если существует подграф, False иначе

Алгоритм (в псевдокоде типа python):

def clique(A, k):
    P = A x A x A //Cartesian product
    for tuple in P:
        if connected(tuple):
            return true
    return false

def connected(tuple):
    unconnected = tuple
    for vertex in tuple:
        for test_vertex in unconnected:
            if vertex is linked to test_vertex:
                remove test_vertex from unconnected
    if unconnected is empty:
        return true
    else:
        return false

Версия 2

input: матрица смежности размером n на n, а k - размер подграфа, чтобы найти

output: все полные подграфы в размера k.

Алгоритм (на этот раз в функциональном псевдокоде Python):

//Base case:  return all vertices in a list since each
//one is a 1-clique
def clique(A, 1):
    S = new list
    for i in range(0 to n-1):
        add i to S
    return S

//Get a tuple representing all the cliques where
//k = k - 1, then find any cliques for k
def clique(A,k):
    C = clique(A, k-1)
    S = new list
    for tuple in C:
        for i in range(0 to n-1):
            //make sure the ith vertex is linked to each
            //vertex in tuple
            for j in tuple:
                if A[i,j] != 1:
                    break
            //This means that vertex i makes a clique
            if j is the last element:
                newtuple = (i | tuple) //make a new tuple with i added
                add newtuple to S
    //Return the list of k-cliques
    return S

Есть ли у кого-нибудь мысли, комментарии или предложения? Это включает ошибки, которые я, возможно, пропустил, а также способы сделать это более читаемым (я не привык к использованию большого псевдокода).

Версия 3

К счастью, я поговорил с моим профессором, прежде чем отправить задание. Когда я показал ему псевдокод, который я написал, он улыбнулся и сказал мне, что я слишком много работал. Во-первых, мне не нужно было вводить псевдокод; Мне просто нужно было продемонстрировать, что я понял проблему. И два, он хотел решения грубой силы. Так что я повернулся, выглядел примерно так:

input: граф G = (V, E), размер клики, чтобы найти k

output: True, если клика существует, false в противном случае

Алгоритм

  • Найти декартово произведение V k.
  • Для каждого кортежа в результате проверьте, подключена ли каждая вершина ко всем другим. Если все подключены, верните true и выйдите.
  • Вернуть false и выйти.

ОБНОВЛЕНИЕ. Добавлена ​​вторая версия. Я думаю, что это становится все лучше, хотя я не добавил никаких фантастических динамических программ (что я знаю).

ОБНОВЛЕНИЕ 2: добавлено несколько комментариев и документации, чтобы сделать версию 2 более удобочитаемой. Вероятно, это версия, в которую я перехожу сегодня. Спасибо за помощь! Хотел бы я принять более одного ответа, но я принял ответ от человека, который помог мне больше всего. Я дам вам понять, что думает мой профессор.

Ответ 1

Некоторые комментарии:

  • Вам нужно только рассмотреть n-select-k комбинаций вершин, а не все k-кортежи (n ^ k из них).
  • connected(tuple) выглядит неправильно. Вам не нужно reset unconnected внутри цикла?
  • Как предложили другие, есть лучшие способы грубого принуждения. Рассмотрим следующее рекурсивное соотношение: A (k + 1) -подграф является кликой, если первые k вершин образуют клику, а вершина (k + 1) смежна с каждой из первых k вершин. Вы можете применить это в двух направлениях:
    • Начните с 1-клики и постепенно расширяйте клику, пока не получите желаемый размер. Например, если m является наибольшей вершиной в текущей клике, попробуйте добавить вершину {m + 1, m + 2,..., n-1}, чтобы получить клику, которая является одной вершиной больше. (Это похоже на обход дерева по глубине, где дочерние элементы дерева node являются вершинами, большими, чем наибольшая вершина в текущей клике.)
    • Начните с подграфа нужного размера и проверьте, является ли это кликой, используя рекурсивное отношение. Настройте таблицу memoization, чтобы сохранить результаты на этом пути.
  • (предложение реализации) Используйте матрицу смежности (0-1) для представления ребер в графе.
  • (начальная обрезка) Отбросьте все вершины со степенью меньше k.

Ответ 2

Я однажды применил алгоритм, чтобы найти все максимальные клики в графе, что является аналогичной проблемой для вас. То, как я это делал, основывалось на этом документе: http://portal.acm.org/citation.cfm?doid=362342.362367 - он описал решение обратной трассировки, которое я нашел очень полезным в качестве руководства, хотя Я сильно изменил эту статью. Вам понадобится подписка, чтобы справиться с этим, но я предполагаю, что у вашего университета будет один доступный.

Одна вещь в этой статье, хотя я действительно думаю, что они должны были назвать "не установленным" "уже рассмотренным множеством", потому что это просто слишком смущает иначе.

Ответ 3

Алгоритм "для каждого k-набора вершин, если он клик, а затем возвращает true" работает точно. Однако это грубая сила, которая, вероятно, не является тем, что ищет алгоритм. Вместо этого учтите следующее:

  • Каждая вершина является 1-кликой.
  • Для каждой 1-клики каждая вершина, которая соединяется с вершиной в 1-клике, вносит 2-клику.
  • Для каждой 2-клики каждая вершина, которая соединяется с каждой вершиной в 2-клике, вносит вклад в 3-клику.
  • ...
  • Для каждого (k-1) -клика каждая вершина, которая соединяется с каждой вершиной в (k-1) клике, способствует k-клике.

Эта идея может привести к лучшему подходу.

Ответ 5

Удивительно, что набирать вещи, как вопрос, покажет вам то, что вы только что написали. Эта строка:

P = A x A x A  //Cartesian product

должно быть следующим:

P = A k//Декартово произведение

Что вы подразумеваете под A ^ k? Вы принимаете матричный продукт? Если да, то A - матрица смежности (вы сказали, что это массив из n + 1 элементов)?

В нотации setbuilder он будет выглядеть примерно так:

P = {(x0, x1,... xk) | x0 ∈ A и x1 ∈ A... и xk ∈ A}

Это в основном просто декартово произведение A взятых k раз. На бумаге я записал ее как k, являющийся надстрочным индексом A (я только что понял, как это сделать, используя markdown).

Плюс, A - это просто массив каждой отдельной вершины без учета смежности.