BOI 2016
CEOI 2017
BOI 2018
BOI 2019
BOI 2020
CEOI 2020
Bosses
Mamy wierzchołków, z których należy zbudować ukorzenione drzewo.
Każdy wierzchołek ma listę wierzchołków, które mogą być jego ojcem.
Dodatkowo każdemu wierzchołkowi należy przypisać wagę tak, by była większa
niż suma wag jego dzieci.
Należy znaleźć drzewo o minimalnej sumie wag.
Rozwiązanie
Załóżmy, że jeżeli mamy już kształ drzewa, to przypisanie wag, żeby
zminimalizować ich sumę, jest bardzo proste.
Zaczynamy od liści, którym przypisujemy , a następnie każdy wierzchołek
wewnętrzny ma wagę równą sumie wag dzieci plus .
Popatrzmy, jak zmieni się sumaryczna waga, gdy do takiego drzewa dodamy
nowy liść na głębokości (zakładamy, że korzeń jest na głębokości 1).
Liść doda do sumarycznej wagi, następnie jego ojciec też doda
i tak dalej: każdy wierzchołek na ścieżce do korzenia doda ,
zatem sumarycznie waga wzrośnie o .
Tak więc widać, że całkowita waga to suma głębokości wszystkich wierzchołków.
Zatem opłaca się, by wierzchołki były położone jak najbliżej korzenia.
Z ograniczeń na dane wynika, że rozwiązanie , gdzie
jest akceptowalne.
To pozwala nam na przeiterowanie się po wszystkich wyborach korzenia drzewa.
Mając wybrany korzeń , resztę wierzchołków można podczepiać zachłannie.
Na początek możemy podczepić wszystkie wierzchołki, dla których może
być ojcem.
Następnie możemy podczepić wszystkie wierzchołki, dla których te nowo
podczepione mogą być ojcem (a nie zostały podczepione wcześniej).
I tak dalej.
Wystarczy zatem dla każdego wierzchołka pamiętać listę tych, które akceptują
jako ojca i zrobić prostego BFS-a w czasie :
const int N = 5100;
int n,k,v;
vector<int> child[N];
int level[N],q[N],qe,qb;
int main() {
scanf("%d",&n);
REP(i,n) {
scanf("%d",&k);
REP(j,k) {
scanf("%d",&v);
child[v-1].push_back(i);
}
}
int best = n*n;
REP(root,n) {
REP(i,n) level[i] = -1;
level[root] = 1;
int total = 1;
qe = qb = 0;
q[qe++] = root;
while (qe != qb) {
int v = q[qb++];
for (int u : child[v]) if (level[u] == -1) {
level[u] = level[v] + 1;
total += level[u];
q[qe++] = u;
}
}
if (qe == n) {
best = min(best, total);
}
}
printf("%d\n", best);
}