【树形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;
}
View Code

 

posted @ 2014-11-03 19:30  mithrilhan  阅读(182)  评论(0编辑  收藏  举报