Для кожного запиту, заданого парою (k_i, v_i) запустимо пошук в глибину або в ширину, починаючи з вершини v_i. При цьому рухатися по графу будемо тільки по ребрам, релевантність яких не менше значення k_i. Порахуємо кількість досягнутих вершин , не рахуючи початкову вершину v_i. Значення і буде відповіддю на запит (k_i, v_i).
Приклад
Фермер Джон встановив наступні зв'язки між відео:
Відео і мають релевантність ,
Відео і — релевантність ,
Відео і — релевантність .
На підставі цих даних можна обчислити релевантність між іншими парами відео:
Відео і : релевантність = min(3, 2) = 2,
Відео і : релевантність = min(3, 4) = 3,
Відео і : релевантність = min(2, 4) = 2.
Тепер розглянемо, які відео будуть рекомендовані при наступних запитах:
З відео при k = 1 будуть рекомендовані відео і .
З відео при k = 3 будуть рекомендовані відео і .
З відео при k = 4 не буде рекомендовано жодне відео.
Реалізація алгоритму — пошук у ширину
Вхідний граф зберігаємо у списку суміжності .
vector<vector<pair<int, int>>> g;Функція bfs реалізує пошук у ширину з вершини і повертає кількість відвіданих вершин, не включаючи саму початкову вершину . У процесі пошуку ми переходимо тільки по тим ребрам, вага яких не менша за задане значення .
int bfs(int start, int k)
{Масив найкоротших відстаней у цій задачі не потрібний — досить лише відстежувати, чи була вершина відвідана. Якщо вершина була відвідана, встановлюємо used[i] = 1.
vector<int> used(n + 1);
used[start] = 1;Ініціалізуємо чергу і додаємо в неї стартову вершину .
queue<int> q;
q.push(start);Кількість відвіданих вершин при пошуку у ширину (не рахуючи початкову вершину ) підраховуємо в змінній .
int res = 0;Запускаємо пошук у ширину.
while (!q.empty())
{Виймаємо вершину з черги .
int v = q.front(); q.pop();Перебираємо ребра, суміжні з вершиною .
for (auto edge : g[v])
{Розглядаємо ребро (v, to) вагою .
int to = edge.first;
int kto = edge.second;Якщо вага ребра менша , то таке ребро не розглядаємо (перехід по ньому заборонений).
if (kto < k) continue;Якщо вершина ще не була відвідана, то додаємо її у чергу, позначаємо як відвідану і збільшуємо лічильник відвіданих вершин на .
if (used[to] == 0)
{
q.push(to);
used[to] = 1;
res++;
}
}
}Повертаємо відповідь на запит.
return res;
}Основна частина програми. Читаємо вхідні дані.
scanf("%d %d", &n, &qu);
g.resize(n + 1);
for (i = 0; i < n - 1; i++)
{
scanf("%d %d %d", &p, &q, &r);Додаємо у список суміжності неорієнтоване ребро вагою .
g[p].push_back({ q, r });
g[q].push_back({ p, r });
}Послідовно обробляємо запитів.
while (qu--)
{
scanf("%d %d", &k, &v);Запускаємо пошук у ширину з вершини . Виводимо кількість вершин, відвіданих в результаті пошуку у ширину.
printf("%d\n", bfs(v, k));
}Реалізація алгоритму – пошук у глибину
Вхідний граф зберігаємо у списку суміжності .
vector<vector<pair<int, int>>> g;Функція dfs виконує пошук у глибину, починаючи з вершини , і повертає кількість відвіданих вершин. У процесі пошуку ми переміщаємося тільки по тим ребрам, у котрих вага не менша за задане значення .
int dfs(int v, int k)
{Позначаємо вершину як відвідану.
used[v] = 1;У змінній підраховуємо кількість вершин, відвіданих у піддереві з коренем у в ході виконання пошуку у глибину.
int res = 1;Перебираємо ребра, суміжні з вершиною .
for (auto edge : g[v])
{Розглядаємо ребро (v, to) вагою .
int to = edge.first;
int kto = edge.second;Якщо вага ребра менша , то таке ребро не розглядаємо (перехід по ньому заборонений).
if (kto < k) continue;Якщо вершина ще не була відвідана, то запускаємо з неї пошук у глибину. Кількість відвіданих вершин у піддереві з коренем додаємо до .
if (used[to] == 0)
res += dfs(to, k);
}
return res;
}Основна частина програми. Читаємо вхідні дані.
scanf("%d %d", &n, &qu);
g.resize(n + 1);
for (i = 0; i < n - 1; i++)
{
scanf("%d %d %d", &p, &q, &r);Додаємо у список суміжності неорієнтоване ребро вагою .
g[p].push_back({ q, r });
g[q].push_back({ p, r });
}Послідовно обробляємо запитів.
while (qu--)
{
scanf("%d %d", &k, &v);Запускаємо пошук у глибину з вершини . Виводимо кількість вершин, відвіданих в результаті пошуку у глибину, не рахуючи саму вершину .
used.assign(n + 1, 0);
printf("%d\n", dfs(v, k) - 1);
}