Mysz zaczyna w dowolnym wierzchołku, następnie przechodzi pewną ścieżką
i opuszcza drzewo w dowolnym wierzchołku.
Może przy tym
Gdy wchodzi do wierzchołka to „spotyka” znajdujące się tam gołębie.
Gdy zaznacza wierzchołek
Następnie kot przechodzi po tej samej ścieżce.
Naszym zadaniem jest tak wybrać ścieżkę i zaznaczanie wierzchołków, żeby zmaksymalizować wartość: liczba gołębi spotkanych przez kota minus liczba gołębi spotkanych przez mysz.
Załóżmy, że mysz porusza się ustaloną ścieżką
Zauważmy, że mysz będzie spotykać tylko gołębie ze ścieżki (choć być może nie wszystkie). Natomiast kot spotka wszystkie gołębie ze ścieżki i być może niektóre z wierzchołków sąsiednich.
Jeżeli mysz jest w wierzchołku
Z kolei dla kota istotne są gołębie z sąsiadów:
jeśli mysz zaznaczy
Podsumowując: zaznaczenie wierzchołka
Można zauważyć, że jeśli ukorzenimy drzewo w wierzchołku
Wystarczy teraz zrobić programowanie dynamiczne o stanie
const int N = 110000, V = 110; int n,k,p[N]; vector<int> adj[N]; ll dp[N][V]; void dfs(int v, int par) { ll sum=0; for (int u : adj[v]) if (u != par) { dfs(u, v); sum += p[u]; } dp[v][0] = 0; REP(i,k) { dp[v][i+1] = 0; for (int u : adj[v]) if (u != par) { dp[v][i+1] = max(dp[v][i+1], sum + dp[u][i]); dp[v][i+1] = max(dp[v][i+1], dp[u][i+1]); } } } int main() { scanf("%d%d",&n,&k); REP(i,n) scanf("%d",&p[i]); REP(i,n-1) { int a,b; scanf("%d%d",&a,&b); --a; --b; adj[a].push_back(b); adj[b].push_back(a); } dfs(0, -1); ll ans = 0; REP(i,k) { ans = max(ans, dp[0][i+1]); } printf("%lld\n", ans); }
Złożoność czasowa tego rozwiązania to
Łatwo jest przerobić to rozwiązanie na program o złożoności
ll ans = 0; REP(root,n) { dfs(root, -1); REP(i,k) { ans = max(ans, dp[root][i+1]); } } printf("%lld\n", ans);
Jeżeli ścieżka nie musi zaczynać się w korzeniu, to może zaczynać się w pewnym
wierzchołku
Analogicznie zatem możemy programowaniem dynamicznym wyznaczyć stany
Aby obliczyć przypadek trzeci (czyli ścieżki przechodzące przez
Szczegóły w poniższym kodzie:
void dfs(int v, int par) { ll sum=0; for (int u : adj[v]) if (u != par) { dfs(u, v); sum += p[u]; } int ppar = par != -1 ? p[par] : 0; dp[v][0] = 0; dp2[v][0] = 0; REP(i,k) { dp[v][i+1] = 0; dp2[v][i+1] = ppar; for (int u : adj[v]) if (u != par) { dp[v][i+1] = max(dp[v][i+1], sum + dp[u][i]); dp[v][i+1] = max(dp[v][i+1], dp[u][i+1]); dp2[v][i+1] = max(dp2[v][i+1], sum - p[u] + ppar + max(dp2[u][i], (ll)p[u])); dp2[v][i+1] = max(dp2[v][i+1], dp2[u][i+1]); } } REP(i,k+1) { for (int u1 : adj[v]) if (u1 != par) { ans = max(ans, dp[u1][i]); if (i) { ans = max(ans, dp[u1][i-1] + ppar + sum); } ans = max(ans, dp2[u1][i]); for (int u2 : adj[v]) if (u2 != par && u1 != u2) { ans = max(ans, dp[u1][i] + dp2[u2][k-i]); if (i) { ans = max(ans, dp[u1][i-1] + ppar + sum - p[u2] + dp2[u2][k-i]); } } } } }
Złożoność czasowa tego rozwiązania to
REP(i,k+1) { Dp[i] = Dp2[i] = 0; } bool first = 1; for (int u : adj[v]) if (u != par) { REP(i,k+1) { ans = max(ans, dp[u][i]); if (i) { ans = max(ans, dp[u][i-1] + ppar + sum); } ans = max(ans, dp2[u][i]); if (!first) { ans = max(ans, dp[u][i] + Dp2[k-i]); ans = max(ans, Dp[i] + dp2[u][k-i]); if (i) { ans = max(ans, dp[u][i-1] + ppar + sum - p[Dp2_v[k-i]] + Dp2[k-i]); ans = max(ans, Dp[i-1] + ppar + sum - p[u] + dp2[u][k-i]); } } } REP(i,k+1) { Dp[i] = max(Dp[i], dp[u][i]); if (dp2[u][i] > Dp2[i]) { Dp2[i] = dp2[u][i]; Dp2_v[i] = u; } } first = 0; }