Вот грубая идея. Но сначала несколько предположений: 1. неориентированный граф 2. постоянный счетчик вершин
Ваш график постоянно меняется. Поэтому необходимо эффективно обновлять количество соседей (ребер) и вторых соседей. Первый тривиален, поэтому давайте посмотрим на вторых соседей.
Согласно предложению @ Patrick, давайте поработаем с A^2
и посмотрим, как его можно эффективно обновить, не перезапуская каждый раз с нуля. A^2_ij
- это число путей длины два от i
до j
, просто имейте в виду, что оно также будет иметь диагональные элементы, потому что всегда есть путь длиной два от вершины к себе. Если у вас есть A^2
, вы можете легко подсчитать количество вторых соседей, поэтому давайте будем постоянно обновлять A^2
в памяти при изменении графика.
Как эффективно обновить A^2
:
Когда вы добавляете / удаляете ребро, вы меняете A
на матрицу B
, в которой есть только две записи. Предположим, мы добавляем (а не удаляем) ребро. Тогда (A+B)^2 = A^2 + AB + BA + B^2
.
Предположим, что добавленное ребро было (i,j)
.
B^2
тривиально: (B^2)_ii = (B^2)_jj = 1
, остальное - 0.
AB = transpose(BA)
поэтому нам нужно вычислить только один из двух, скажем BA
. Получается, что строка i
из BA
является строкой j
из A
, а строка j
из BA
является строкой i
из A
, остальное равно нулю. Итак, снова, это быстро вычислить.
Удаление краев будет аналогичным.
Вам нужно только считать вторых соседей, поэтому вместо подсчета количества ненулевых недиагональных элементов, которые A^2
имеет на каждом шаге, с некоторой дополнительной работой вы можете посчитать, насколько количество ненулевых записей изменяется в A^2
при добавлении AB + BA
.
EDIT
Все это объясняется на другом языке:
Давайте отследим количество путей длины два между любыми двумя вершинами в матрице M
. Когда мы добавляем (удаляем) ребро между i
и j
, количество путей длины два будет увеличиваться (уменьшаться) на единицу между i
и всеми соседями j
, а также j
и всеми Соседи i
, поэтому M
легко обновлять через O(n)
раз после каждого изменения графика.