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,
Ə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:
to_1 zirvəsini çıxarın və kökü to_2 olan alt ağacdakı zirvələri rekursiv olaraq xilas edin. Xilas edilən zirvələrin sayı sum[to_1] - 1 + dp[to_2] olacaq.
to_2 zirvəsini çıxarın və kökü to_1 olan alt ağacdakı zirvələri rekursiv olaraq xilas edin. Xilas edilən zirvələrin sayı sum[to_2] - 1 + dp[to_1] olacaq.
İ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,
Buradan
Buna görə də,
zirvəsinin oğulları üzərində iterasiya edərək hesablayırıq
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,
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]);