MuTub (Gümüş)#10422

MuTub (Gümüş) (Həll təhlili)

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:

Bu məlumatlar əsasında digər video cütlükləri arasında əlaqəlilik hesablana bilər:

İndi aşağıdakı sorğular üçün hansı videoların tövsiyə ediləcəyinə baxaq:

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);
}