Знаете ли вы какой-нибудь алгоритм (лучше, чем грубая сила), который может находить вершины в графе, которые разделены одной вершиной и не связаны между собой. Пример:
На этом графике найдены пути:
Лучшим был бы код на С ++, который использует массив списков stl в качестве представления графа, но код на любом другом процедурном языке или псевдокоде также подойдет.
Один из способов будет основан на поиске в ширину, где для каждой вершины i
на графике мы сканируем вершины, смежные с вершинами, смежными с i
(то есть два уровня смежности!).
mark = array[0..n-1] of 0
flag = 1
for i = nodes in graph do
// mark pattern of nodes adjacent to i
mark[i] = flag
for j = nodes adjacent to i do
mark[j] = flag
endfor
// scan nodes adjacent to those adjacent to i
// (separated by one vertex!)
for j = nodes adjacent to i do
for k = nodes adjacent to j do
if mark[k] != flag and k > i then
// i,k are separated by another vertex
// and there is no edge i,k
// prevent duplicates
mark[k] = flag
endif
endfor
endfor
// implicit unmarking of current pattern
flag += 1
endfor
Если бы граф имел m
ребер на вершину, это было бы O(n * m^2)
алгоритм, который требует O(n)
дополнительное пространство
Одно простое и интуитивно понятное решение этой проблемы заключается в матрице смежности. Как мы знаем, (i, j) -й элемент n-й степени матрицы смежности перечисляет все пути длины ровно n между i и j.
Поэтому я просто читаю в A матрицу смежности, а затем вычисляю A ^ 2. Наконец, я перечисляю все пары, которые имеют ровно один путь длины 2 между ними.
//sg
#include<stdio.h>
#define MAX_NODE 10
int main()
{
int a[MAX_NODE][MAX_NODE],c[MAX_NODE][MAX_NODE];
int i,j,k,n;
printf("Enter the number of nodes : ");
scanf("%d",&n);
for(i=0;i<n;i++)
for(j=0;j<=i;j++)
{
printf("Edge from %d to %d (1 yes/0 no) ? : ",i+1,j+1);
scanf("%d",&a[i][j]);
a[j][i]=a[i][j]; //undirected graph
}
//dump the graph
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
c[i][j]=0;
printf("%d",a[i][j]);
}
printf("\n");
}
printf("\n");
//multiply
for(i=0;i<n;i++)
for(j=0;j<n;j++)
for(k=0;k<n;k++)
{
c[i][j]+=a[i][k]*a[k][j];
}
//result of the multiplication
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
printf("%d",c[i][j]);
}
printf("\n");
}
for(i=0;i<n;i++)
for(j=0;j<=i;j++)
{
if(c[i][j]==1&&(!a[i][j])&&(i!=j)) //list the paths
{
printf("\n%d - %d",i+1, j+1 );
}
}
return 0;
}
Пробный прогон для вашего графика
[aman@aman c]$ ./Adjacency2
Enter the number of nodes : 5
Edge from 1 to 1 (1 yes/0 no) ? : 0
Edge from 2 to 1 (1 yes/0 no) ? : 1
Edge from 2 to 2 (1 yes/0 no) ? : 0
Edge from 3 to 1 (1 yes/0 no) ? : 1
Edge from 3 to 2 (1 yes/0 no) ? : 1
Edge from 3 to 3 (1 yes/0 no) ? : 0
Edge from 4 to 1 (1 yes/0 no) ? : 0
Edge from 4 to 2 (1 yes/0 no) ? : 0
Edge from 4 to 3 (1 yes/0 no) ? : 1
Edge from 4 to 4 (1 yes/0 no) ? : 0
Edge from 5 to 1 (1 yes/0 no) ? : 0
Edge from 5 to 2 (1 yes/0 no) ? : 0
Edge from 5 to 3 (1 yes/0 no) ? : 0
Edge from 5 to 4 (1 yes/0 no) ? : 1
Edge from 5 to 5 (1 yes/0 no) ? : 0
01100
10100
11010
00101
00010
21110
12110
11301
11020
00101
4 - 1
4 - 2
5 - 3
Анализ
Для n вершин:
Время: O (n ^ 3). Может быть уменьшено до O (N ^ 2,32), что очень хорошо
Пробел: O (n ^ 2).
Вы можете сделать это с адаптированной версией Алгоритм Варшалла. Алгоритм в следующем примере кода использует матрицу смежности вашего графа и печатает i j
если там
это край от i
в k
и край от k
в j
но нет прямого пути от i
в j
,
#include <iostream>
int main() {
// Adjacency Matrix of your graph
const int n = 5;
bool d[n][n] = {
{ 0, 1, 1, 0, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 0, 0, 1, 0 },
{ 0, 0, 0, 0, 1 },
{ 0, 0, 0, 0, 0 },
};
// Modified Warshall Algorithm
for (int k = 0; k < n; k++)
for (int i = 0; i < n; i++)
if (d[i][k])
for (int j = 0; j < n; j++)
if (d[k][j] && !d[i][j])
std::cout << i + 1 << " " j + 1 << std::endl;
}
Вы можете просмотреть результат онлайн.