Запустим пошук вглиб з вершини , де знаходиться дім Кефи. В одному з параметрів функції dfs будемо зберігати кількість поспіль вершин з котами. Якщо у вершині це число перевищить , подальший пошук вглиб з цієї вершини не виконуємо. Підраховуємо кількість відвідуваних листків. Вершина є листком, якщо її ступінь дорівнює і при цьому вона не є коренем (тобто вершиною ).
Приклад
Розглянемо дерева з першого та другого прикладів.
У першому прикладі Кефа може пройти поспіль тільки через одну вершину з котом. Він зможе потрапити у ресторани, розташовані у вершинах та .
У другому прикладі Кефа може пройти поспіль тільки через дві вершини з котами. Він зможе потрапити у ресторани, розташовані у вершинах та .
Реалізація алгоритму
Розташування котів зберігаємо в масиві . Дерево зберігаємо у списку суміжності .
vector<int> cats;
vector<vector<int> > g;Функція dfs виконує пошук вглиб з вершини і повертає кількість ресторанів, до яких можна дістатися з цієї вершини (за умови що на шляху до них зустрічається не більше поспіль вершин з котами). Попередником вершини є вершина . Кількість поспіль вершин з котами, пройдених включно до вершини , дорівнює .
int dfs(int v, int prev, int cnt)
{Якщо вже пройдено більше котів поспіль, то подальший пошук вглиб з вершини не продовжується.
if (cnt > m) return 0;Якщо ми знаходимося у листі, то збільшуємо кількість ресторанів, до яких можна потрапити.
if (g[v].size() == 1 && prev != -1) return 1;У змінній підраховуємо кількість ресторанів, досяжних з вершини .
int res = 0;Перебираємо всі ребра (v, to), що виходять з . Якщо вершина є попередником , то не переходимо в цю вершину.
for (int to : g[v])
if (to != prev)
{Якщо у вершині немає кота, встановлюємо c = 0. У противному випадку присвоюємо c = cnt + 1. Змінна зберігає кількість поспіль вершин з котами до вершини включно.
int c = (cats[to] == 0) ? 0 : cnt + 1;Запускаємо пошук вглиб з вершини .
res += dfs(to, v, c);
}Повертаємо результат.
return res;
}Основна частина програми. Читаємо вхідні дані.
scanf("%d %d", &n, &m);
cats.resize(n + 1);
for (i = 1; i <= n; i++)
scanf("%d", &cats[i]);Будуємо дерево.
g.resize(n + 1);
for (i = 1; i < n; i++)
{
scanf("%d %d", &a, &b);
g[a].push_back(b);
g[b].push_back(a);
}Виводимо відповідь. Функція dfs, викликана з вершини , повертає відповідь на задачу. Оскільки у вершини немає предка, другим параметром передаємо значення . Розпочавши з вершини , ми відвідали котів.
printf("%d\n", dfs(1, -1, cats[1]));Python реалізація
Функція dfs виконує пошук вглиб з вершини і повертає кількість ресторанів, до яких можна дістатися з цієї вершини (за умови що на шляху до них зустрічається не більше поспіль вершин з котами). Попередником вершини є вершина . Кількість поспіль вершин з котами, пройдених включно до вершини , дорівнює .
def dfs(v, prev, cnt):Якщо вже пройдено більше котів поспіль, то подальший пошук вглиб з вершини не продовжується.
if cnt > m:
return 0Якщо ми знаходимося у листі, то збільшуємо кількість ресторанів, до яких можна потрапити.
if len(g[v]) == 1 and prev != -1:
return 1У змінній підраховуємо кількість ресторанів, досяжних з вершини .
res = 0Перебираємо всі ребра (v, to), що виходять з . Якщо вершина є попередником , то не переходимо в цю вершину.
for to in g[v]:
if to != prev:Якщо у вершині немає кота, встановлюємо c = 0. У противному випадку присвоюємо c = cnt + 1. Змінна зберігає кількість поспіль вершин з котами до вершини включно.
c = 0 if cats[to] == 0 else cnt + 1Запускаємо пошук вглиб з вершини .
res += dfs(to, v, c)Повертаємо результат.
return resОсновна частина програми. Читаємо вхідні дані.
n, m = map(int, input().split())
cats = [0] + list(map(int, input().split()))Будуємо дерево.
g = [[] for _ in range(n + 1)]
for _ in range(n - 1):
a, b = map(int, input().split())
g[a].append(b)
g[b].append(a)Виводимо відповідь. Функція dfs, викликана з вершини , повертає відповідь на задачу. Оскільки у вершини немає предка, другим параметром передаємо значення . Розпочавши з вершини , ми відвідали котів.
print(dfs(1, -1, cats[1]))