Parade
Explicación
Queremos hallar un camino en el árbol con la máxima cantidad de aristas adyacentes que no forman parte del camino.
Cualquier camino simple en un árbol enraizado sigue una de dos formas generales:
- Solo sube hacia la raíz (desde el nodo más bajo hasta el más alto del camino).
- Sube hacia la raíz y luego baja de nuevo.
Como cada camino tiene un único nodo más alto, podemos comprobar para cada nodo cuáles son los mejores caminos para cada caso si es el nodo más alto de ese camino. Haremos esto con programación dinámica.
Sean y la cantidad máxima de aristas adyacentes para cada caso con como el nodo más alto. Si es el conjunto de hijos de , entonces valen las siguientes recurrencias:
Podemos calcular ambos valores de forma eficiente llevando la cuenta de los dos mejores valores de mientras iteramos por .
Como el camino debe tener longitud no nula, también necesitamos restar 1 de la respuesta si el grafo es una estrella (es decir, un árbol con hojas).
Implementación
Complejidad temporal:
#include <bits/stdc++.h>
using namespace std;
vector<int> graph[200001];
int dp[2][200001];
void dfs(int node = 1, int parent = 0) {
int mx1 = 1, mx2 = 1;
for (int i : graph[node])
if (i != parent) {
dfs(i, node);
if (dp[0][i] >= mx1) {
mx2 = mx1;
mx1 = dp[0][i];
} else mx2 = max(mx2, dp[0][i]);
}
dp[0][node] = mx1 + graph[node].size() - 2;
dp[1][node] = mx1 + mx2 + graph[node].size() - 3;
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int n;
cin >> n;
for (int i = 1; i < n; i++) {
int a, b;
cin >> a >> b;
graph[a].push_back(b);
graph[b].push_back(a);
}
int leaves = 0;
for (int i = 1; i <= n; i++)
if (graph[i].size() == 1) leaves++;
dfs();
int ans = 0;
for (int i = 1; i <= n; i++) {
if (graph[i].size() > 1) ans = max(ans, max(dp[1][i], dp[0][i]) + 1);
}
// Comprobamos si el grafo es una estrella para restar 1
cout << ans - (leaves == n - 1);
return 0;
}