Colorazione dell'albero#11002

Colorazione dell'albero (Editoriale)

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:

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

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 .

void~dfs2(int~v,~int p,~long~long~s)

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:

  1. Supponiamo che come primo passo venga scelto il vertice . Trovate il numero di punti ottenuti.

  2. Spostate la radice dal vertice al vertice e calcolate il numero di punti ottenuti.

  3. 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);