Kəpənəyin Arxasınca Qaçış#11058

Kəpənəyin Arxasınca Qaçış (Həll təhlili)

Dərinlik üzrə keçməyi təpəsindən başlayaraq icra edək. Hər bir təpə üçün iki dəyəri hesablayacağıq:

Daha sonra ikinci dərinlik üzrə keçməyi başladaq. Bu keçmə zamanı dəyərini hesablayacağıq — təpəsində köklü alt ağacda bəzi yarpaqlarda yerləşdirilməli olan minimum dost sayını, belə ki, kəpənəyi mütləq tutmaq olar, əgər o, bu alt ağacı seçərsə.

Əgər h[v] \le d[v]-dirsə, onda res[v] = 1. Bu halda, təpəsinin alt ağacında minimum dərinliyi olan yarpağa bir dostu yerləşdirmək kifayətdir: o, ağacın kökündən çıxaraq keçmədən əvvəl təpəsinə çatacaq.

Əks halda, əgər to_1, to_2, ..., to_k — təpəsinin övladlarıdırsa, onda

res[v] = res[to_1] + res[to_2] + ... + res[to_k]

Əgər kəpənək təpəsinin özündə tutulmazsa, -dən çıxan alt ağaclardakı hər hansı birindən onu tutmaq üçün hazır olmalıdırlar.

Tələb olunan cavab dəyəridir.

Nümunə

Birinci nümunədə (şəkilin sol tərəfində) iki dost lazımdır, onların iki çıxışda yerləşdirilməli olduğu yerdə. Kəpənək ya təpə -dən təpə -yə və ya təpə -ə uça bilər. Hər hansı bir halda, onu alınacaq.

İkinci nümunədə (şəkilin sağ tərəfində) bir dost kifayətdir, onu iki çıxışdan birinə — təpə və ya -ə yerləşdirmək olar. Bir dəqiqə ərzində kəpənək təpə -dən təpə -yə çatacaq. Eyni zamanda dostu təpə -yə çatacaq və onu orada tutacaq.

Növbəti nümunəyə baxaq. Kəpənəyi tutmaq üçün üç dost lazımdır.

Alqoritmin icrası

Sonsuzluq və işçi massivləri elan edək.

#define INF 2000000000
vector<vector<int> > g;
vector<int> d, h, res;

dfs funksiyası (v, p, cnt) dərinlik üzrə keçməni təpəsindən başlayır və dəyərini qaytarır. Burada — təpəsinin əcdadı, və — təpəsindən -ə qədər olan məsafədir. Keçmə prosesi zamanı hər bir təpəsi üçün və dəyərləri hesablanır.

int dfs(int v, int p = -1, int cnt = 0)
{

dəyəri, təpəsindən -ə olan məsafə, -də saxlanılır.

  d[v] = cnt;
  int height = INF;

təpəsinin bütün övladlarını nəzərdən keçiririk. v \to to olan qövsü nəzərdən keçiririk. Əgər -in əcdadı ilə eynidirsə (to = p), növbəti övlada keçirik.

  for (int to : g[v])
    if (to != p) 

dəyişənində aşağıdakı dəyəri hesablayırıq

min(h[to_1], h[to_2], ..., h[to_k]),

burada to_1, to_2, ..., to_k — təpəsinin övladlarıdır.

height = min(height, dfs(to, v, cnt + 1));

Əgər height = INF, bu təpəsinin yarpaq olduğunu və h[v] = 0-ı təyin etməyin lazım olduğunu bildirir. Əks halda,

h[v] = 1 + min(h[to_1], h[to_2], ..., h[to_k])

funksiya geriyə qaytarır

  return h[v] = (height == INF) ? 0 : 1 + height;
}

dfs2 funksiyası dərinlik üzrə keçməni təpəsindən başlayır və -i qaytarır. Burada — təpəsinin əcdadıdır.

int dfs2(int v, int p = -1)
{
  int s = 0;

Qoy to_1, to_2, ..., to_k — təpəsinin övladlarıdır. dəyişənində aşağıdakı cəmi hesablayacağıq:

res[to_1] + res[to_2] + ... + res[to_k]
  for (int to : g[v])
    if (to != p)
    {
      dfs2(to, v);
      s += res[to];
    }

Əgər h[v] \le d[v]-dirsə, bir dost kifayətdir, və res[v] = 1. Əks halda

res[v] = res[to_1] + res[to_2] + ... + res[to_k] = s
  return res[v] = (h[v] <= d[v]) ? 1 : s;
}

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

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

Massivləri başladırıq.

d.resize(n + 1);
h.resize(n + 1);
res.resize(n + 1);

İki dərinlik üzrə keçmə işə salırıq. Birinci keçmə hər bir təpəsi üçün və dəyərlərini hesablayır.

dfs(1);
dfs2(1);

Cavabı çıxırıq — kəpənəyi tutmaq üçün lazım olan minimum dost sayını.

printf("%lld\n", res[1]);