Ağacın rənglənməsi#11002

Ağacın rənglənməsi (Həll təhlili)

Qazanılan xalların sayı birmənalı şəkildə seçilən birinci təpə ilə müəyyən olunur. Buna görə də bütün mümkün başlanğıc təpələri yoxlamaq, hər biri üçün yekun xal sayını hesablamaq və maksimum qiyməti seçmək kifayətdir.

təpəsindən dərinliyə axtarış işə salaq və weight[v] — kökü təpəsində olan alt ağacın ölçüsünü (yəni alt ağacındakı təpələrin sayını) hesablayaq. Tutaq ki, to_1, to_2, ..., to_k — -nin oğullarıdır. Onda aşağıdakı düstur doğrudur:

weight[v] = 1 + weight[to_1] + weight[to_2] + ... + weight[to_k]

İkinci dərinliyə axtarış bütün təpələr üzrə yerinə yetirilir və verilmiş təpədən oyuna başladıqda əldə edilə biləcək maksimum xal sayını yenidən hesablamağa imkan verir.

dfs2 funksiyasına baxaq. Tutaq ki, biz təpəsindəyik, onun valideyni isə təpəsidir. Əgər birinci hərəkətdə təpəsi seçilərsə, qazanılan xalların sayı -ə bərabərdir.

void~dfs2(int~v,~int p,~long~long~s)

(v, to) kənarı boyunca keçid edək və təpəsindən oyuna başladıqda cavabın necə hesablanacağını göstərək. Faktiki olaraq biz ağacın yenidən asılmasını (переподвешивание) yerinə yetiririk: kök təpəsindən təpəsinə köçürülür.

Solda kökü -də olan ağac təsvir olunub. təpəsi onun nəvələrindən (potomoklarından) biridir, isə onun əcdadıdır. Sağda isə kökü -da olan ağac göstərilib.

Sağdakı ağac üçün weight[to]-nu hesablamaq üçün soldakı ağacda olan qiymətindən soldakı ağacın weight[to]-sunu çıxmaq və nöqtəli xətlə işarələnmiş sahədəki təpələrin sayını əlavə etmək lazımdır. Bu say n - weight[to]-ya bərabərdir.

Misal

Tutaq ki, seçilən birinci təpə -dir. Onda qazanılan xalların sayı olacaq.

Əgər seçilən birinci təpə olarsa, qazanılan xalların sayı -ya bərabər olacaq. təpəsindən təpəsinə keçidi aşağıdakı kimi yerinə yetirək: s = 25 qiymətindən weight[2] = 4 qiymətini çıxaq və (9 - weight[4]) = 5 əlavə edək. Nəticədə 25 - 4 + 5 = 26 alınır, bu da kökü təpəsində olan ağac üçün qiymətidir.

Maksimum xal sayı -ya bərabərdir və oyuna təpəsindən başlandıqda əldə edilir.

Məşq

Aşağıdakı ağaca baxaq:

  1. Tutaq ki, birinci hərəkətdə təpəsi seçilib. Qazanılan xalların sayını tapın.

  2. Kökü təpəsindən təpəsinə köçürün və qazanılan xalların sayını hesablayın.

  3. Sonra kökü -dən -ə, -dən -ə və -dən -ya köçürün. Əldə edilən məsələlərin hər birini həll edin.

Alqoritmin realizasiyası

Qrafın qonşuluq siyahısını elan edək .

vector<vector<int>> g;
vector<int> weight;

dfs1 funksiyası təpəsindən dərinliyə axtarışı yerinə yetirir, onun valideyni təpəsidir. Bu zaman weight[v] — kökü təpəsində olan alt ağacın ölçüsü, yəni bu alt ağacdakı təpələrin sayı hesablanır.

void dfs1(int v, int p)
{
  weight[v] = 1;
  for (int to : g[v])
    if (to != p)
    {
      dfs1(to, v);
      weight[v] += weight[to];
    }
}

dfs2 funksiyası təpəsindən dərinliyə axtarışı yerinə yetirir, onun valideyni təpəsidir. Əgər oyunun birinci hərəkətində təpəsi seçilərsə, qazanılan xalların sayı olacaq.

void dfs2(int v, int p, long long s)
{
  res = max(res, s);
  for (int to : g[v])
    if (to != p) dfs2(to, v, s - weight[to] + n - weight[to]);
}

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

scanf("%d", &n);
g.resize(n + 1);
weight.resize(n + 1);
for (i = 1; i < n; i++)
{
  scanf("%d %d", &a, &b);
  g[a].push_back(b);
  g[b].push_back(a);
}

təpəsindən dərinliyə axtarışı işə salırıq.

dfs1(1, 0);

dəyişənində weight massivindəki bütün ədədlərin cəmini hesablayırıq. Bu qiymət, əgər oyunda birinci təpəsi seçilərsə, qazanılan xalların sayına bərabərdir.

s = 0;
for (i = 1; i <= n; i++)
  s += weight[i];

təpəsindən ikinci dərinliyə axtarışı işə salırıq.

dfs2(1, 0, s);

Cavabı çap edirik.

printf("%lld\n", res);