Kinoya getmək#4463

Kinoya getmək (Həll təhlili)

Hər hansı iki şəhər arasında düz bir yol olduğundan, ölkənin yol şəbəkəsi ağac əmələ gətirir. Ümumi xərcləri minimuma endirmək üçün Çipin və Deylin mümkün qədər tez görüşməsi sərfəlidir. Bu, onlar ən yaxın ümumi əcdadlarında görüşdükdə baş verəcək, bundan sonra onlar kinoteatrın yerləşdiyi paytaxta birlikdə taksi ilə gedə biləcəklər.

Alqoritmin realizasiyası

Ən yaxın ümumi əcdadı (LCA) tapmaq üçün ikilik qalxma metodu istifadə olunur. Qraf massivində qonşuluq siyahısı şəklində saxlanılır. LCA alqoritminin işləməsi üçün lazımi qlobal massivlər də elan olunur:

#define MAX 100010
#define LOGMAX 18
vector<int> g[MAX];
int timer, d[MAX], f[MAX], dist[MAX];
int up[MAX][LOGMAX];

dfs funksiyası təpəsindən başlayaraq ağacın dərinliyə görə gəzintisini yerinə yetirir. təpəsi təpəsinin valideynidir. Paytaxtdan (nömrəsi olan təpədən) təpəsinə qədər olan məsafə -ə bərabərdir; bu qiymət dist[v] massivində saxlanılır. Gəzinti prosesində həmçinin təpəyə giriş və çıxış vaxt möhürləri — və hesablanır.

void dfs (int v, int p = 1, int len = 0) 
{
  d[v] = timer++;

təpəsinin bilavasitə valideynini saxlayırıq.

  up[v][0] = p; 

Kökdən (paytaxtdan) təpəsinə qədər olan məsafəni saxlayırıq.

  dist[v] = len;

İkilik əcdadlar cədvəlini qururuq.

  for (int i = 1; i <= l; i++)
    up[v][i] = up[up[v][i-1]][i-1];

təpəsindən qonşu təpələrə bütün mümkün keçidlər nəzərdən keçirilir. ilə (v, to) ağac tili ilə birləşdirilmiş hər təpəsi üçün keçid yerinə yetirilir.

  for (int to : g[v])
    if (to != p) dfs (to, v, len + 1);
  f[v] = timer++;
}

Parent funksiyası, əgər təpəsi təpəsinin əcdadıdırsa, doğru qaytarır.

int Parent(int a, int b)
{
  return (d[a] <= d[b]) && (f[a] >= f[b]);
}

LCA funksiyası ağacda iki və təpəsinin ən yaxın ümumi əcdadını (LCA) ikilik qalxma metodu və əcdadlar cədvəli vasitəsilə hesablayır.

int LCA (int a, int b) 
{
  if (Parent(a, b)) return a;
  if (Parent(b, a)) return b;
  for (int i = l; i >= 0; i--)
    if (!Parent(up[a][i], b)) a = up[a][i];
  return up[a][0];
}

Proqramın əsas hissəsi. Giriş məlumatlarını oxuyuruq.

scanf("%d %d",&n,&Price);

l = ⌈log_2n⌉ qiymətini hesablayırıq.

l = 1;
while ((1 << l) <= n)  l++;

Məsələnin şərtinə görə ağac olan yönəldilməmiş qrafı qururuq.

for(i = 0; i < n - 1; i++)
{
  scanf("%d %d",&x,&y);
  g[x].push_back(y);
  g[y].push_back(x);
}

Ağac üzərində kinoteatrın yerləşdiyi paytaxtdan başlayaraq dərinliyə görə axtarış işə salırıq.

dfs(1);

sorğunu ardıcıl olaraq emal edirik.

scanf("%d",&q);
for(i = 0; i < q; i++)
{
  scanf("%d %d",&x,&y);
  lca = LCA(x, y);

Görüşənə qədər Çip dist[x] - dist[lca] km, Deyl isə dist[y] - dist[lca] km yol qət edəcək. Birlikdə taksidə onlar düz dist[lca] km yol qət edəcəklər.

  Chip = dist[x] - dist[lca];
  Deil = dist[y] - dist[lca];

Yekun xərcləri hesablayıb çap edirik.

  printf("%.5lf %.5lf\n", (Chip + dist[lca] / 2.0) * Price, 
          (Deil + dist[lca] / 2.0) * Price);
}