Maksimal məbləğ ağacda#973

Maksimal məbləğ ağacda (Həll təhlili)

Güman edək ki, — ağacın zirvəsidir. Aşağıdakıları qeyd edək:

Beləliklə, problemi cavabı, zirvə -i ağacın kökü kimi qəbul etdikdə, max(dp_1(1), dp_2(1)) olacaq.

Tərtib olunan funksiyaları rekursiv olaraq təyin edək:

dp_1(v) = c_v + \sum_{i=1}^k dp_2(to_i) , burada~to_1, ..., to_k - zirvənin~v~oğlanlarıdır.
dp_2(v) = \sum_{i=1}^k max(dp_1(to_i), dp_2(to_i)), burada~to_1, ..., to_k - zirvənin~v~oğlanlarıdır.

Əgər - c_v pulu olan bir yarpaqdırsa, onda funksiyalar aşağıdakı qiymətləri alacaq: dp_1(v) = c_v və dp_2(v) = 0.

Nümunə

Zirvələrdəki dp_1(v) / dp_2(v) etiketlərini qoyaq nümunələrin ağaclarına.

Birinci nümunə üçün:

İkinci nümunə üçün:

Tapşırıq

Ağacın zirvələrində dp_1(v) / dp_2(v) etiketlərini qoyun:

Alqoritmin həyata keçirilməsi

İş səviyyələri elan edək.

vector<vector<int> > g;
vector<int> dp1, dp2, cost;

dfs funksiyası dərinliyi axtarışı həyata keçirir. dp_1 və dp_2 qiymətlərini ağacın bütün zirvələrində hesablayaq.

void dfs(int v, int p = -1)
{
  dp1[v] = cost[v];
  dp2[v] = 0;

  for (int to : g[v])
  {
    if (to == p) continue;

    dfs(to, v);

    dp1[v] += dp2[to];
    dp2[v] += max(dp1[to], dp2[to]);
  }
}

Proqramın əsas hissəsi. Ağacı və pul səviyyəsini oxuyuruq.

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

dp1.resize(n+1); dp2.resize(n+1);
cost.resize(n+1);
for(i = 1; i <= n; i++)
  scanf("%d",&cost[i]);

Tutaq ki, ağacın kökü zirvə -də yerləşir. Oradan dərindən axtarışa başlayırıq.

dfs(1);

Cavabı hesablayırıq və çıxarırıq.

ans = max(dp1[1], dp2[1]);
printf("%d\n",ans);