Yoluxmuş ağac#11724

Yoluxmuş ağac (Həll təhlili)

Hər bir zirvəsi üçün o zirvənin kök olduğu alt ağacdakı zirvələrin sayını hesablayın. to_1, to_2, ..., to_k - zirvəsinin oğlanlarıdırsa,

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

Əgər zirvəsi ağacın bir yarpaq zirvəsidirsə, onda sum[v] = 1.

Qoy hazırda yoluxmuş olan və yoluxmuşlar arasında yalnız zirvəsi olan alt ağacdakı xilas edilən zirvələrin sayını göstərsin.

Əgər zirvəsinin yalnız bir oğulu varsa, o zaman dp[v] = sum[to] - 1 (çıxarılan zirvəsi xilas edilmiş olmaz).

Qoy zirvəsinin iki oğulu to_1 və to_2 olsun (hər bir zirvənin dərəcəsi 3-dən böyük deyil). Onda iki variantımız var:

İki variantdan xilas edilən zirvələrin sayının çox olduğu variant seçilməlidir.

Dərinliklə axtarış prosesini, (v, to) kənarı nəzərə alındığı zaman nəzərdən keçirək.

Qoy - zirvəsinin ikinci oğulu olsun. Biz dp[to] + sum[a] - 1 dəyərini hesablamalıyıq. Onu yalnız və zirvələrini istifadə edərək tapaq. Belə bilirik ki,

sum[v] = 1 + sum[to] + sum[a]

Buradan

sum[a] = sum[v] - sum[to] - 1

Buna görə də,

dp[to] + sum[a] - 1 = dp[to] + sum[v] - sum[to] - 2

zirvəsinin oğulları üzərində iterasiya edərək hesablayırıq

dp[v] = max(dp[to] + sum[v] - sum[to] - 2)

Məsələn

Birinci nümunədə Hüseyn və nömrəli zirvələri xilas edə bilər, birinci gedişində nömrəli zirvəni seçməklə.

İkinci nümunəni nəzərə alaq. Hər bir zirvəsinin yanında sum[v] / dp[v] işarələrini qoyaq. Hüseyn tərəfindən seçilən zirvələr yaşıl rənglərlə göstərilmişdir.

Məsələn,

dp[1] = max(sum[2] - 1 + dp[5], sum[5] - 1 + dp[2]) = max(2, 2) = 2, \\ sum[1] = 1 + sum[2] + sum[5] = 1 + 3 + 3 = 7

Alqoritmin həyata keçirilməsi

İşçi massivləri elan edək.

#define MAX 300005
int sum[MAX], dp[MAX];
vector<vector<int>> g;

dfs funksiyası zirvəsindən dərinlik axtarışını həyata keçirir. zirvəsinin atası -dir.

void dfs(int v, int p = -1)
{

və dəyərlərini startlaşdırırıq.

  sum[v] = 1;
  dp[v] = 0;

zirvəsinin oğullarından dərinlik axtarışını başlayırıq.

  for (int to : g[v])
    if (to != p)
    {
      dfs(to, v);
      sum[v] += sum[to];
    }

dəyərini hesablayırıq.

  for (int to : g[v])
    if (to != p)
    {
      dp[v] = max(dp[v], sum[to] - 1); // əgər 1 oğul varsa
      dp[v] = max(dp[v], dp[to] + sum[v] - sum[to] - 2);
    }
}

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

scanf("%d", &n);
g.clear(); g.resize(n + 1);
memset(dp, 0, sizeof(dp));
memset(sum, 0, sizeof(sum));
for (i = 1; i < n; i++)
{
  scanf("%d %d", &u, &v);
  g[u].push_back(v);
  g[v].push_back(u);
}

1 nömrəli zirvədən dərinlik axtarışına başlayırıq.

dfs(1);

Cavabı çıxarırıq.

printf("%d\n", dp[1]);