Il cammino più breve in un albero pesato può essere trovato tramite una ricerca in profondità o in ampiezza (in questo caso non è necessario utilizzare l'algoritmo di Dijkstra).
Per trovare il cammino più lungo (il diametro dell'albero) procediamo come segue:
Eseguiamo una ricerca in ampiezza a partire dal primo vertice. Troviamo il vertice , per il quale il cammino sarà il più lungo.
Successivamente eseguiamo una ricerca in ampiezza a partire dal vertice e determiniamo il vertice , per il quale il cammino sarà anch'esso il più lungo.
Il cammino da a è il più lungo nell'albero (il diametro dell'albero).
Esempio
L'albero presentato nell'esempio ha il seguente aspetto:
Eseguiamo una ricerca in ampiezza a partire dal vertice (a sinistra). Il cammino più lungo sarà fino al vertice .
Successivamente eseguiamo una ricerca in ampiezza a partire dal vertice (a destra). Il cammino più lungo risulterà essere fino al vertice , la sua lunghezza è pari a .
Implementazione dell'algoritmo
Dichiariamo la lista di adiacenza del grafo .
Dichiariamo l'array delle distanze più brevi .
vector<vector<pair<int, int>>> g;
vector<long long> d;La funzione bfs esegue una ricerca in ampiezza a partire dal vertice .
int bfs(int v)
{
deque<int> q;
q.push_back(v);
while (!q.empty())
{
int v = q.front(); q.pop_front();
for (auto x : g[v])
{
int to = x.first;
int w = x.second;
if (d[to] == -1)
{
d[to] = d[v] + w;
q.push_back(to);
}
}
}Restituiamo il numero del vertice per il quale la distanza dal vertice è massima.
return max_element(d.begin() + 1, d.begin() + n + 1) - d.begin();
}Parte principale del programma. Leggiamo i dati in input. Costruiamo il grafo.
scanf("%d", &n);
g.resize(n + 1);
for (i = 0; i < n - 1; i++)
{
scanf("%d %d %lld", &b, &e, &dist);
g[b].push_back({ e, dist });
g[e].push_back({ b, dist });
}Inizializziamo l'array delle distanze più brevi.
d = vector<long long>(n + 1, -1);
d[1] = 0;Eseguiamo la prima ricerca in ampiezza a partire dal vertice . Determiniamo il vertice , che si trova più lontano da .
int v = bfs(1);Inizializziamo nuovamente l'array delle distanze più brevi e avviamo la seconda ricerca in ampiezza, a partire dal vertice .
d = vector<long long>(n + 1, -1);
d[v] = 0;
v = bfs(v);Stampiamo la risposta — la lunghezza del cammino più lungo.
printf("%lld\n", d[v]);Implementazione dell'algoritmo — ricerca in profondità
Memorizziamo la lista di adiacenza del grafo nell'array .
Per memorizzare le distanze più brevi dichiariamo l'array .
vector<vector<pair<int, int>> > g;
vector<long long> dist;La funzione dfs esegue una ricerca in profondità a partire dal vertice . Il vertice è il predecessore di nel processo di ricerca in profondità.
void dfs(int v, int p = -1)
{Esaminiamo tutti gli archi adiacenti al vertice .
for (auto x : g[v])
{Consideriamo l'arco v → to con peso .
int to = x.first;
int w = x.second;Se to \ne p, ricalcoliamo dist[to] e richiamiamo la ricerca in profondità a partire dal vertice .
if (to != p)
{
dist[to] = dist[v] + w;
dfs(to, v);
}
}
}Parte principale del programma. Leggiamo i dati in input. Costruiamo il grafo.
scanf("%d", &n);
g.resize(n + 1);
for (i = 0; i < n - 1; i++)
{
scanf("%d %d %d", &b, &e, &w);
g[b].push_back({ e, w });
g[e].push_back({ b, w });
}Eseguiamo una ricerca in profondità a partire dal vertice . Riempiamo l'array delle distanze più brevi a partire dal vertice .
dist.assign(n + 1, -1);
dist[1] = 0;
dfs(1);Determiniamo il vertice , la cui distanza dal vertice è massima.
v = max_element(dist.begin(), dist.end()) - dist.begin();Eseguiamo la seconda ricerca in profondità, a partire dal vertice . Riempiamo l'array delle distanze più brevi a partire dal vertice .
dist.assign(n + 1, -1);
dist[v] = 0;
dfs(v);Il valore massimo nell'array è pari al diametro dell'albero.
v = max_element(dist.begin(), dist.end()) - dist.begin();Stampiamo la risposta.
printf("%lld\n", dist[v]);Implementazione in Python
from collections import dequeLeggiamo i dati in input. Memorizziamo la lista di adiacenza del grafo in .
Dichiariamo la lista delle distanze più brevi .
n = int(input())
g = [[] for _ in range(n + 1)]
d = [-1] * (n + 1)Costruiamo il grafo.
for _ in range(n - 1):
b, e, dist = map(int, input().split())
g[b].append((e, dist))
g[e].append((b, dist))La funzione bfs esegue una ricerca in ampiezza a partire dal vertice .
def bfs(v):
q = deque()
q.append(v)
while q:
v = q.popleft()
for to, w in g[v]:
if d[to] == -1:
d[to] = d[v] + w
q.append(to)Restituiamo il numero del vertice per il quale la distanza dal vertice è massima.
return d.index(max(d))Eseguiamo la prima ricerca in ampiezza a partire dal vertice . Determiniamo il vertice , che si trova più lontano da .
d[1] = 0
v = bfs(1)Inizializziamo l'array delle distanze più brevi e avviamo la seconda ricerca in ampiezza a partire dal vertice .
d = [-1] * (n + 1)
d[v] = 0
v = bfs(v)Stampiamo la risposta — la lunghezza del cammino più lungo.
print(d[v])