Il numero di punti ottenuti è univocamente determinato dal primo vertice scelto. Pertanto, è sufficiente esaminare tutti i possibili vertici di partenza, calcolare per ciascuno di essi il numero finale di punti e scegliere il valore massimo.
Eseguiamo una ricerca in profondità a partire dal vertice e calcoliamo il valore weight[v] — la dimensione del sottoalbero con radice nel vertice (cioè il numero di vertici nel sottoalbero di ). Siano to_1, to_2, ..., to_k i figli di . Allora vale la formula:
Il secondo attraversamento in profondità viene eseguito su tutti i vertici e permette di ricalcolare il numero massimo di punti che si possono ottenere se si inizia la partita da un dato vertice.
Consideriamo la funzione dfs2. Supponiamo di trovarci nel vertice , e che il suo genitore sia il vertice . Se come primo passo viene scelto il vertice , allora il numero di punti ottenuti è uguale a .
Eseguiamo la transizione lungo l'arco (v, to) e mostriamo come calcolare la risposta se si inizia la partita dal vertice . In sostanza, stiamo eseguendo un ri-radicamento dell'albero: la radice viene spostata dal vertice al vertice .
A sinistra è raffigurato l'albero con radice in . Il vertice è uno dei suoi discendenti, e — il suo predecessore. A destra è mostrato l'albero con radice in .
Per calcolare weight[to] per l'albero di destra, è necessario sottrarre dal valore dell'albero di sinistra weight[to] dell'albero di sinistra e aggiungere il numero di vertici nella regione indicata dalla linea tratteggiata. Questo numero è uguale a n - weight[to].
Esempio
Supponiamo che il primo vertice scelto sia . Allora il numero di punti ottenuti sarà .
Se il primo vertice scelto fosse , il numero di punti ottenuti sarebbe . Eseguiamo la transizione dal vertice al vertice nel modo seguente: sottraiamo da s = 25 il valore weight[2] = 4 e aggiungiamo (9 - weight[4]) = 5. Di conseguenza otteniamo 25 - 4 + 5 = 26, il valore di per l'albero con radice nel vertice .
Il numero massimo di punti è uguale a e si ottiene se si inizia la partita dal vertice .
Esercizio
Consideriamo il seguente albero:
Supponiamo che come primo passo venga scelto il vertice . Trovate il numero di punti ottenuti.
Spostate la radice dal vertice al vertice e calcolate il numero di punti ottenuti.
Successivamente spostate la radice da a , da a e da a . Risolvete ciascuno dei problemi ottenuti.
Implementazione dell'algoritmo
Dichiariamo la lista di adiacenza del grafo .
vector<vector<int>> g;
vector<int> weight;La funzione dfs1 esegue una ricerca in profondità a partire dal vertice , il cui genitore è il vertice . In questo caso viene calcolato weight[v] — la dimensione del sottoalbero con radice nel vertice , cioè il numero di vertici in questo sottoalbero.
void dfs1(int v, int p)
{
weight[v] = 1;
for (int to : g[v])
if (to != p)
{
dfs1(to, v);
weight[v] += weight[to];
}
}La funzione dfs2 esegue una ricerca in profondità a partire dal vertice , il cui genitore è il vertice . Se come primo passo della partita viene scelto il vertice , allora il numero di punti ottenuti sarà .
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]);
}Parte principale del programma. Leggiamo i dati in input. Costruiamo il grafo.
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);
}Avviamo la ricerca in profondità a partire dal vertice .
dfs1(1, 0);Nella variabile calcoliamo la somma di tutti i numeri nell'array weight. Questo valore è uguale al numero di punti ottenuti nel caso in cui venga scelto per primo nella partita il vertice .
s = 0;
for (i = 1; i <= n; i++)
s += weight[i];Avviamo la seconda ricerca in profondità a partire dal vertice .
dfs2(1, 0, s);Stampiamo la risposta.
printf("%lld\n", res);