Нехай dp[v][x] — кількість вершин, що знаходяться на відстані від вершини в піддереві з коренем у . Покладемо dp[v][0] = 1, оскільки на відстані від вершини знаходиться тільки сама вершина .
Нехай вершина має синів u_1, u_2, ..., u_p. Тоді кількість вершин, що знаходяться на відстані від вершини в піддереві з коренем у , дорівнює сумі кількості вершин, що знаходяться на відстані x - 1 від кожної з вершин u_1, u_2, ..., u_p.
Розглянемо піддерево з коренем у вершині . Порахуємо кількість шляхів довжини , повністю лежачих у цьому піддереві і проходящих через вершину . Розіб'ємо такі шляхи на дві групи:
шляхи, що починаються у вершині . Їх кількість дорівнює dp[v][k].
шляхи, що проходять через вершину , кінці яких розташовані в піддеревах синів вершини .
Розглянемо шлях довжини , проходящий через корінь піддерева . Нехай відстань від вершини до одного з кінців шляху дорівнює x~(1 \le x \le k - 1). Припустимо, що цей кінець знаходиться у піддереві певного сина u_1. Тоді відстань від вершини до другого кінця шляху дорівнює k - x, причому другий кінець може знаходитися в будь-якому іншому піддереві, відмінному від піддерева з коренем у u_1.
Якщо відстань від першого кінця шляху до вершини дорівнює , то відстань від цього кінця до вершини u_1 дорівнює x - 1. Число способів вибрати такий перший кінець дорівнює dp[u_1][x - 1].
Число способів вибрати другий кінець шляху дорівнює кількості вершин, що знаходяться на відстані k - x від вершини , але не належать піддереву з коренем у u_1. Це кількість дорівнює
Згідно з правилом добутку, загальна кількість таких шляхів дорівнює
Таким чином, загальна кількість таких шляхів дорівнює
Залишається просумувати зазначене вираз по всім вершинам дерева.
Приклад
Розглянемо дерево, наведене в прикладі.
Реалізація алгоритму
В масиві зберігається представлення дерева у вигляді списків суміжності. Масив використовується для реалізації динамічного програмування.
vector<vector<int> > g;
vector<vector<int> > dp;Функція dfs виконує пошук в глибину, починаючи з вершини . Значення позначає предка вершини . В процесі обходу будуємо масив .
void dfs(int v, int p = -1)
{Ініціалізуємо масив .
dp[v].resize(k+1);
dp[v][0] = 1;Перебираємо всі вершини , в які можна перейти з вершини .
for (int to : g[v])
{
if (to == p) continue;
dfs(to,v);
for(int x = 1; x <= k; x++)
dp[v][x] += dp[to][x-1];
}
}Функція dfsRes виконує пошук в глибину, починаючи з вершини , і призначена для обчислення шуканої відповіді.
void dfsRes(int v, int p = -1)
{
for (int to : g[v])
{
if (to == p) continue;
dfsRes(to,v);
for(int x = 1; x < k; x++)
resA += 1LL * dp[to][x-1] * (dp[v][k-x] - dp[to][k-x-1]);
}
resB += dp[v][k];
}Основна частина програми. Читаємо вхідні дані. Будуємо дерево.
scanf("%d %d",&n,&k);
g.resize(n+1);
for (i = 0; i < n - 1; i++)
{
scanf("%d %d",&a,&b);
g[a].push_back(b);
g[b].push_back(a);
}Першим пошуком в глибину будуємо масив .
dp.resize(n+1);
dfs(1);Підраховуємо та виводимо шукану відповідь.
resA = resB = 0;
dfsRes(1);
res = resA / 2 + resB;
printf("%lld\n",res);Python реалізація
Функція dfs виконує пошук в глибину, починаючи з вершини . Значення vdp. \begin{lstlisting}[language=Python] def dfs(v, p): \end{lstlisting} Ініціалізуємо масив dp[v]. \begin{lstlisting}[language=Python] dp[v] = [0] * (k + 1) dp[v][0] = 1 \end{lstlisting} Перебираємо всі вершини tov. \begin{lstlisting}[language=Python] for to in g[v]: if to == p: continue dfs(to, v) for x in range(1, k + 1): dp[v][x] += dp[to][x - 1] \end{lstlisting} Функція \textbf{dfsRes} виконує пошук в глибину, починаючи з вершини v, і призначена для обчислення шуканої відповіді. \begin{lstlisting}[language=Python] def dfsRes(v, p): global resA, resB for to in g[v]: if to == p: continue dfsRes(to, v) for x in range(1, k): resA += dp[to][x - 1] * (dp[v][k - x] - dp[to][k - x - 1]) resB += dp[v][k] \end{lstlisting} Основна частина програми. Читаємо кількість вершин дерева nk. \begin{lstlisting}[language=Python] n, k = map(int, input().split()) \end{lstlisting} У списку gdp використовується для реалізації динамічного програмування. \begin{lstlisting}[language=Python] g = [[] for _ in range(n + 1)] dp = [[] for _ in range(n + 1)] \end{lstlisting} Читаємо список ребер. Будуємо дерево. \begin{lstlisting}[language=Python] for _ in range(n - 1): a, b = map(int, input().split()) g[a].append(b) g[b].append(a) \end{lstlisting} Першим пошуком в глибину будуємо масив dp$.
dfs(1, -1)Підраховуємо та виводимо шукану відповідь.
resA, resB = 0, 0
dfsRes(1, -1)
res = resA // 2 + resB
print(res)