Hər bir (k_i, v_i) cütündən ibarət olan sorğu üçün v_i təpəsindən başlayaraq dərinlik üzrə (DFS) və ya enlik üzrə (BFS) axtarış başlatacağıq. Bu müddətdə, yalnız əlaqəliliyi k_i-dən az olmayan kənarlarla qrafda hərəkət edəcəyik. Başlanğıc təpəsi v_i çıxılmaqla çatan təpələrin sayını kimi hesablayacağıq. dəyəri (k_i, v_i) sorğusunun cavabı olacaq.
Nümunə
Fərmer John videolar arasında aşağıdakı əlaqələri qurmuşdur:
Video və -nin əlaqəliliyi -dür,
Video və -ün əlaqəliliyi -dir,
Video və -ün əlaqəliliyi -dür.
Bu məlumatlar əsasında digər video cütlükləri arasında əlaqəlilik hesablana bilər:
Video və : əlaqəlilik = min(3, 2) = 2,
Video və : əlaqəlilik = min(3, 4) = 3,
Video və : əlaqəlilik = min(2, 4) = 2.
İndi aşağıdakı sorğular üçün hansı videoların tövsiyə ediləcəyinə baxaq:
Video -dən k = 1 zamanı videolar və tövsiyə edilir.
Video -dən k = 3 zamanı videolar və tövsiyə edilir.
Video -dən k = 4 zamanı heç bir video tövsiyə edilmir.
Alqoritmin İcrası — Enlik üzrə Axtarış
Daxil olunan qrafı qonşuluq siyahısında saxlayırıq .
vector<vector<pair<int, int>>> g;bfs funksiyası başlanğıc nöqtəsi olan və özündən ayrı təpəsini qaytaran enlik üzrə axtarış həyata keçirir. Axtarış zamanı yalnız -dən az olmayan kənarlarla hərəkət edirik.
int bfs(int start, int k)
{Bu məsələdə ən qısa məsafə arrayına ehtiyac yoxdur — yalnız nöqtənin ziyarət olunub-olunmadığını izləmək kifayətdir. Əgər nöqtəsi ziyarət olunarsa, used[i] = 1 təyin edirik.
vector<int> used(n + 1);
used[start] = 1;Növbəni başlatırıq və başlanğıc nöqtəsi -ı ona əlavə edirik.
queue<int> q;
q.push(start);Enlik üzrə axtarış zamanı ənki nöqtələrinin sayını (başlanğıc nöqtəsi -ı saymamaqla) dəyişənində hesablayırıq.
int res = 0;Enlik üzrə axtarışa başlayırıq.
while (!q.empty())
{Nöqtəni növbədən çıxarırıq .
int v = q.front(); q.pop();Nöqtə ilə yaxından əlaqəli olan kənarları nəzərdən keçiririk.
for (auto edge : g[v])
{(v, to) kənarını çəkisi ilə nəzərdən keçiririk.
int to = edge.first;
int kto = edge.second;Əgər çəki kənarı -dən azdırsa, bu kənarı nəzərə almırıq (bu yolla keçişə icazə verilmir).
if (kto < k) continue;Əgər təpəsi hələ ziyarət olunmayıbsa, növbəyə əlavə edirik, ziyarət olunmuş kimi qeyd edirik və ziyarət olunmuş təpələrin sayını -də artırırıq.
if (used[to] == 0)
{
q.push(to);
used[to] = 1;
res++;
}
}
}Sorğuya cavab qaytarırıq.
return res;
}Proqramın əsas hissəsi. Daxil verilənləri oxuyuruq.
scanf("%d %d", &n, &qu);
g.resize(n + 1);
for (i = 0; i < n - 1; i++)
{
scanf("%d %d %d", &p, &q, &r);Qonşuluq siyahısına yönləndirilməmiş kənarını çəki ilə əlavə edirik.
g[p].push_back({ q, r });
g[q].push_back({ p, r });
}Sonra sorğuları ardıcıl emal edirik.
while (qu--)
{
scanf("%d %d", &k, &v);Başlanğıc təpəsi ilə enlik üzrə axtarışa başlayırıq. Enlik üzrə axtarış nəticəsində ziyarət olunan təpələrin sayını çap edirik.
printf("%d\n", bfs(v, k));
}Alqoritmin İcrası – Dərinlik üzrə Axtarış
Daxil olunan qrafı qonşuluq siyahısında saxlayırıq .
vector<vector<pair<int, int>>> g;dfs funksiyası başlanğıc nöqtəsi başlamaqla dərinlik üzrə axtarış edir və ziyarət olunan nöqtələrin sayını qaytarır. Axtarış zamanı yalnız çəki -dən az olmayan kənarlarla hərəkət edirik.
int dfs(int v, int k)
{Təpə ziyarət olunmuş kimi qeyd edilir.
used[v] = 1;Dərinlik üzrə axtarış icrasında kök ilə altqrafda ziyarət olunmuş təpələrin sayını -də hesablayırıq.
int res = 1;Nöqtə ilə əlaqəli kənarları nəzərdən keçiririk.
for (auto edge : g[v])
{(v, to) kənarını çəkisi ilə nəzərdən keçiririk.
int to = edge.first;
int kto = edge.second;Əgər çəki kənarı -dən azdırsa, bu kənarı nəzərə almırıq (bu yolla keçişə icazə verilmir).
if (kto < k) continue;Əgər nöqtəsi hələ ziyarət olunmayıbsa, dərinlik üzrə axtarışa buradan başlayırıq. Kök ilə altqrafda ziyarət olunmuş təpələrin sayını -ə əlavə edirik.
if (used[to] == 0)
res += dfs(to, k);
}
return res;
}Proqramın əsas hissəsi. Daxil verilənləri oxuyuruq.
scanf("%d %d", &n, &qu);
g.resize(n + 1);
for (i = 0; i < n - 1; i++)
{
scanf("%d %d %d", &p, &q, &r);Qonşuluq siyahısına yönləndirilməmiş kənarını çəki ilə əlavə edirik.
g[p].push_back({ q, r });
g[q].push_back({ p, r });
}Sonra sorğuları ardıcıl emal edirik.
while (qu--)
{
scanf("%d %d", &k, &v);Başlanğıc nöqtəsi ilə dərinlik üzrə axtarışa başlayırıq. Dərinlik üzrə axtarış nəticəsində ziyarət olunan təpələrin sayını çap edirik, başlanğıc nöqtəsi çıxılmaqla.
used.assign(n + 1, 0);
printf("%d\n", dfs(v, k) - 1);
}