【树形DP】Codeforces 219d Choosing Capital for Treeland
通道:http://codeforces.com/problemset/problem/219/D
题意:有n个城市,它们之间有n-1条路(路都是单向的),形成一棵树。现在可以改变一些路的方向,选择一个首都,使得从首都出发能达其它城市,所需要重建的路的数量最少
思路:考虑每个节点,他的花费是儿子中加上来自父亲的,那么两遍dfs即可,dp2[v] = dp1[u] - dp1[v] - G[i].w + dp2[u] + (G[i].w == 0 ? 1 : 0);
代码:
#include <cstdio> #include <cstring> const int MAX_N = 200007; struct Node { int v, w, nxt; Node () { } Node (int _v, int _w, int _n) { v = _v; w = _w; nxt = _n; } }; int dp1[MAX_N], dp2[MAX_N]; int head[MAX_N], edgecnt; Node G[MAX_N << 1]; int v[MAX_N]; void Clear() { edgecnt = 0; memset(head, -1, sizeof head); } void add(int u, int v, int w) { G[edgecnt] = Node(v, w, head[u]); head[u] = edgecnt++; } int n; void dfs1(int u, int fa) { for (int i = head[u]; ~i; i = G[i].nxt) { int v = G[i].v; if (v == fa) continue; dfs1(v, u); dp1[u] += dp1[v] + G[i].w; } } void dfs2(int u, int fa) { for (int i = head[u]; ~i; i = G[i].nxt) { int v = G[i].v; if (v == fa) continue; dp2[v] = dp1[u] - dp1[v] - G[i].w + dp2[u] + (G[i].w == 0 ? 1 : 0); dfs2(v, u); } } int main() { scanf("%d", &n); Clear(); for (int i = 1; i < n; ++i) { int u, v; scanf("%d%d", &u, &v); add(u, v, 0); add(v, u, 1); } dfs1(1, -1); dfs2(1, -1); int ans = 0x3f3f3f3f; int cnt = 0; for (int i = 1; i <= n; ++i) if (dp1[i] + dp2[i] < ans) { ans = dp1[i] + dp2[i]; cnt = 0; v[cnt++] = i; } else if (dp1[i] + dp2[i] == ans) v[cnt++] = i; printf("%d\n", ans); for (int i = 0; i < cnt; ++i) printf("%d ", v[i]); return 0; }