Граф з вершин є деревом тоді і тільки тоді, коли:
Граф зв'язний. Запустимо пошук в глибину з першої вершини. Підрахуємо кількість відвіданих вершин в процесі пошуку. Якщо воно дорівнює , то граф є зв'язним.
|V| = |E| + 1. Якщо граф є деревом, то він містить n - 1 ребро.
Граф не містить циклів. Запустимо пошук в глибину з першої вершини. Якщо існує зворотне ребро, то граф має цикл і не є деревом.
Виконання умов і або і достатньо для того, щоб граф був деревом.
Приклад
Граф, наведений у прикладі, є деревом.
Реалізація алгоритму — перевірка умов 1) і 3)
Оголосимо матрицю суміжності графа та масив .
#define MAX 110
int g[MAX][MAX], used[MAX];Функція dfs реалізує пошук в глибину з вершини . Предком вершини є . Змінна стане рівною , якщо буде виявлено цикл.
void dfs(int v, int p)
{Якщо граф вже не є деревом (flag = 1), то немає сенсу продовжувати пошук.
if (flag) return;Позначаємо вершину як пройдену.
used[v] = 1;Відвідана вершина , збільшуємо на .
c++;Ребро буде зворотним і утворюватиме цикл, якщо i \ne p і при цьому вершина вже була пройдена (used[i] = 1). У разі виявлення циклу встановимо flag = 1. Якщо циклу немає, то продовжуємо пошук з вершини .
for(int i = 0; i < n; i++)
if ((i != p) && g[v][i])
if(used[i]) flag = 1; else dfs(i,v);
}Основна частина програми. Читаємо вхідні дані.
scanf("%d",&n);
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
scanf("%d",&g[i][j]);У змінній підраховуємо кількість відвіданих вершин при пошуку в глибину. Встановимо flag = 0, якщо в графі немає циклу. При виявленні циклу стане рівним .
c = 0;
flag = 0;Усі вершини спочатку є непройденими (обнуляємо масив ).
memset(used,0,sizeof(used));Запускаємо пошук в глибину з нульової вершини. Оскільки вона є коренем дерева пошуку, то не має батька. Як другий аргумент передаємо функції dfs значення .
dfs(0,-1);Граф не буде деревом, якщо існує зворотне ребро (flag = 1) або граф не є зв'язним (c \ne n).
if (flag || (c != n)) printf("NO\n"); else printf("YES\n");Реалізація алгоритму — перевірка умов 1) і 2)
Оголосимо матрицю суміжності графа та масив .
#define MAX 101
int g[MAX][MAX], used[MAX];Функція dfs реалізує пошук в глибину з вершини .
void dfs(int v)
{Позначаємо вершину як пройдену.
used[v] = 1;Відвідана вершина , збільшуємо на .
c++;Перебираємо вершини , куди можна рухатись з . Переміщення з в можливе, якщо:
існує ребро , тобто g[v][i] = 1;
вершина ще не пройдена (used[i] = 0)
Якщо обидві умови справджуються, то продовжуємо пошук в глибину з вершини .
for (int i = 1; i <= n; i++)
if (g[v][i] && !used[i]) dfs(i);
}Основна частина програми. Читаємо вхідне значення .
scanf("%d", &n); Кількість ребер у графі підраховуємо в змінній .
Edges = 0;Усі вершини спочатку є непройденими (обнуляємо масив ).
memset(used, 0, sizeof(used));Читаємо матрицю суміжності . Підраховуємо кількість ребер у графі.
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
{
scanf("%d", &g[i][j]);
Edges += g[i][j];
}Оскільки граф неорієнтований, то ребра та вважаються однаковими. Поділимо значення на .
Edges /= 2;У змінній підраховуємо кількість відвіданих вершин при пошуку в глибину.
c = 0;Запускаємо пошук в глибину з вершини .
dfs(1);Граф є деревом, якщо кількість ребер у ньому дорівнює n - 1, а також якщо він зв'язний (c = n).
if ((Edges == n - 1) && (c == n)) printf("YES\n");
else printf("NO\n");Java реалізація
import java.util.*;
//import java.io.*;
public class Main
{
static int c = 0;
static int m[][], used[];
static void dfs(int v)
{
used[v] = 1; c++;
for(int i = 0; i < m.length; i++)
if (m[v][i]== 1 && used[i] == 0) dfs(i);
}
public static void main(String[] args) //throws IOException
{
Scanner con = new Scanner(System.in);
//Scanner con = new Scanner(new FileReader ("977.in"));
int n = con.nextInt();
m = new int[n][n];
used = new int[n];
Arrays.fill(used, 0);
int Edges = 0;
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
{
m[i][j] = con.nextInt();
Edges += m[i][j];
}
dfs(0); Edges /= 2;
if ((Edges == n - 1) && (c == n))
System.out.printf("YES");
else
System.out.printf("NO");
}
} Python реалізація — перевірка умов 1) і 3)
Функція dfs реалізує пошук в глибину з вершини . Предком вершини є . Змінна стане рівною , якщо буде виявлено цикл.
def dfs(v, p):Оголосимо глобальні змінні, що використовуються функцією.
global flag, cЯкщо граф вже не є деревом (flag = 1), то немає сенсу продовжувати пошук.
if flag: returnПозначаємо вершину як пройдену.
used[v] = 1Відвідана вершина , збільшуємо на .
c += 1Ребро буде зворотним і утворюватиме цикл, якщо i \ne p і при цьому вершина вже була пройдена (used[i] = 1). У разі виявлення циклу встановимо flag = 1. Якщо циклу немає, то продовжуємо пошук з вершини .
for i in range(n):
if i != p and g[v][i]:
if used[i]: flag = 1
else: dfs(i, v)Основна частина програми. Читаємо вхідне значення .
n = int(input())У змінній підраховуємо кількість відвіданих вершин при пошуку в глибину. Встановимо flag = 0, якщо в графі немає циклу. При виявленні циклу стане рівним .
c = 0
flag = 0Усі вершини спочатку є непройденими (список заповнюємо нулями).
used = [0] * nСтворимо матрицю суміжності , спочатку заповнюємо її нулями.
g = [[0] * n for _ in range(n)]Читаємо вхідну матрицю суміжності.
for i in range(n):
g[i] = list(map(int, input().split()))Запускаємо пошук в глибину з вершини .
dfs(0, -1)Граф не буде деревом, якщо існує зворотне ребро (flag = 1) або граф не є зв'язним (c \ne n).
if flag or c != n:
print("NO")
else:
print("YES")Python реалізація — перевірка умов 1) і 2)
Функція dfs реалізує пошук в глибину з вершини .
def dfs(v):
global cПозначаємо вершину як пройдену.
used[v] = 1Відвідана вершина , збільшуємо на .
c += 1Перебираємо вершини , куди можна рухатись з . Переміщення з в можливе, якщо:
існує ребро , тобто g[v][i] = 1;
вершина ще не пройдена (used[i] = 0)
Якщо обидві умови справджуються, то продовжуємо пошук в глибину з вершини .
for i in range(1, n + 1):
if g[v][i] and not used[i]: dfs(i)Основна частина програми. Читаємо вхідне значення .
n = int(input())Кількість ребер у графі підраховуємо в змінній .
Edges = 0Усі вершини спочатку є непройденими (список заповнюємо нулями).
used = [0] * (n + 1)Створимо матрицю суміжності , спочатку заповнюємо її нулями.
g = [[0] * (n + 1) for _ in range(n + 1)]Читаємо матрицю суміжності . У змінній підраховуємо кількість ребер у графі.
for i in range(1, n + 1):
g[i] = [0] + list(map(int, input().split()))
Edges += sum(g[i])Оскільки граф неорієнтований, то ребра та вважаються однаковими. Поділимо значення на .
Edges //= 2У змінній підраховуємо кількість відвіданих вершин при пошуку в глибину.
c = 0Запускаємо пошук в глибину з вершини .
dfs(1)Граф є деревом, якщо кількість ребер у ньому дорівнює n - 1, а також якщо він зв'язний (c = n).
if Edges == n - 1 and c == n:
print("YES")
else:
print("NO")