Эффективно найти все связанные индуцированные подграфы

существует ли эффективный (*) алгоритм для поиска всех связанных (индуцированных) подграфов Связного неориентированного вершинного графа?

(*) Я понимаю, что в общем случае любой такой алгоритм может иметь сложность O (2^n), потому что для клики (Kn) существует 2^n связанных подграфов. Однако графики, с которыми я обычно имею дело, будут иметь гораздо меньше связанных подграфов, поэтому я ищу способ их генерации без необходимости рассматривать все 2^n подграфов и бросать прочь те, которые не связаны (как в решении этот вопрос).

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

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

1 ответов


в рекурсивном псевдокоде алгоритм 2^n равен

GenerateAndTest(verticesNotYetConsidered, subsetSoFar):
    if verticesNotYetConsidered is empty:
        yield subsetSoFar if it induces a connected subgraph
    else:
        choose a vertex v in verticesNotYetConsidered
        GenerateAndTest(verticesNotYetConsidered - {v}, subsetSoFar)
        GenerateAndTest(verticesNotYetConsidered - {v}, subsetSoFar union {v})

не имеет значения, какая вершина V выбрана; мы даже можем выбирать по-разному в двух братских вызовах. Мы используем эту свободу для получения почти линейного алгоритма Времени (N раз больше числа решений) путем обрезки дерева рекурсии.

если subsetSoFar пусто, тогда выбор по-прежнему не ограничен. В противном случае мы выбираем v быть рядом с одной из вершин в subsetSoFar. Если нет такого v существует, мы уступаем subsetSoFar и return, так как в этом поддереве нет других решений.

обратите внимание на новый инвариант, что subsetSoFar всегда подключен, поэтому мы можем исключить явный тест подключения. Мы делаем O (n) работу на каждом узле дерева рекурсии(наивно O (n^2), но мы можем поддерживать множество соседних вершин постепенно), которое является полным двоичным и чьи листья дают ровно одно решение, поэтому общая работа такова, как утверждалось (напомним, что число внутренних вершин узлы на один меньше, чем количество листьев).

из-за нового инварианта не получается отключенного подграфа.

каждый подключенный подграф выдается. Для набора вершин S, который индуцирует связный подграф, следуйте ветвям, которые согласуются с S. Для правильного подмножества S невозможно не иметь смежности с остальной частью S, поэтому S не обрезается.

новый псевдокод выглядит следующим образом. N(v) обозначает множество соседей v.

GenerateConnectedSubgraphs(verticesNotYetConsidered, subsetSoFar, neighbors):
    if subsetSoFar is empty:
        let candidates = verticesNotYetConsidered
    else
        let candidates = verticesNotYetConsidered intersect neighbors
    if candidates is empty:
        yield subsetSoFar
    else:
        choose a vertex v from candidates
        GenerateConnectedSubgraphs(verticesNotYetConsidered - {v},
                                   subsetSoFar,
                                   neighbors)
        GenerateConnectedSubgraphs(verticesNotYetConsidered - {v},
                                   subsetSoFar union {v},
                                   neighbors union N(v))

EDIT: для графиков максимальной степени O (1) мы можем сделать это действительно линейным временем, поддерживая verticesNotYetConsidered intersect neighbors, чего я не делал для ясности. Эта оптимизация, вероятно, не стоит многого, если вы используете word-parallelism, представляя граф как матрицу смежности, где каждая строка хранится как растровое изображение одного или двух слов.