11263. Четное
дерево
Задано дерево – простой связный
граф без циклов.
Найдите максимальное количество
ребер, которое можно удалить из дерева так, чтобы получился лес, в котором
каждая компонента связности содержала четное число вершин.
Например, в дереве
с 4 вершинами можно удалить не более 1 ребра, чтобы
получился четный лес.
Вход. Первая строка содержит два целых
числа n (2 ≤ n ≤ 100, n четное) – количество вершин, и m –
количество ребер. Каждая из следующих m строк содержит по два целых
числа – номера вершин, соединенные ребром. Корнем дерева является
вершина 1.
Выход. Выведите наибольшее возможное
количество удаленных ребер.
Пример
входа |
Пример
выхода |
10 9 2 1 3 1 4 3 5 2 6 1 7 2 8 6 9 8 10 8 |
2 |
графы - поиск в глубину
В задаче следует
совершить декомпозицию дерева на компоненты связности с четным числом вершин.
При этом следует максимизировать количество этих компонент.
Запустим поиск в
глубину из вершины 1, которая является корнем дерева. Для каждой вершины v определим
количество вершин в поддереве с корнем v. Если это количество четное, то удалим ребро, соединяющее v с его предком при
поиске в глубину.
Для корня (вершины
1) размер всего дерева четный. Однако ребра, соединяющего вершину 1 с ее предком,
не существует. Поэтому из результата, полученного по выше приведенному
алгоритму, следует вычесть 1.
Пример
Рассмотрим
дерево, приведенное в примере. Рядом с
каждой вершиной указан размер поддерева, если рассматривать эту вершину в
качестве корня. Вершины 1, 3 и 6 имеют поддеревья с четным количеством вершин. Поскольку
вершина 1 является корнем и не имеет ребра, ведущего к предку, мы удаляем два
ребра: (1, 3) и (1, 6).
Дерево распалось
на 3 компоненты связности, каждая из которых содержит четное количество вершин.
Объявим рабочие
массивы.
#define MAX 101
int g[MAX][MAX], used[MAX];
Функция dfs совершает поиск в глубину из вершины v и возвращает количество вершин в
поддереве с корнем v.
int dfs(int v)
{
used[v] = 1;
В переменной s вычисляем количество вершин в поддереве с корнем v.
int s = 1;
Перебираем сыновей i вершины v. Прибавляем к s значения dfs(i).
for (int i = 1;
i <= n; i++)
if (g[v][i]
&& !used[i]) s += dfs(i);
Если размер поддерева s четный, удаляем ребро между v и его предком.
if (s % 2 == 0) res++;
Возвращаем количество вершин в поддереве с корнем v.
return s;
}
Основная часть программы. Читаем входные данные. Строим граф.
scanf("%d %d", &n, &m);
for (i = 0; i < m; i++)
{
scanf("%d %d", &a, &b);
g[a][b] = g[b][a] = 1;
}
Запускаем поиск в глубину из вершины 1. В переменной res подсчитываем
количество удаленных ребер.
res = 0;
dfs(1);
Ребра из 1 в его предка не существует. Выводим res – 1.
printf("%d\n", res - 1);
Функция dfs совершает поиск в глубину из вершины v и возвращает количество вершин в
поддереве с корнем v.
def dfs(v):
used[v] = 1
В переменной s вычисляем количество вершин в поддереве с корнем v.
s = 1
Перебираем сыновей i вершины v. Прибавляем к s значения dfs(i).
for i in range(1, n + 1):
if g[v][i] and not used[i]:
s += dfs(i)
Если размер поддерева s четный, удаляем ребро между v и его предком.
if s % 2 == 0:
global res
res += 1
Возвращаем количество вершин в поддереве с корнем v.
return s
Основная часть программы. Читаем входные данные. Строим граф.
n, m = map(int, input().split())
g = [[0] * (n + 1) for _ in range(n + 1)]
used = [0] * (n + 1)
for _ in range(m):
a,
b = map(int, input().split())
g[a][b] = g[b][a] = 1
Запускаем поиск в глубину из вершины 1. В переменной res подсчитываем
количество удаленных ребер.
res = 0
dfs(1)
Ребра из 1 в его предка не существует. Выводим res – 1.
print(res - 1)