codeforces 218D Choosing Capital for Treeland 树形DP

来源:互联网 发布:json在线格式化 php 编辑:程序博客网 时间:2024/05/23 19:17

给一个有向树每条边可以改变方向求改变的最小边数使其最后连通
先dfs一下求出以1为根的每个点与儿子联通的最小改变数
然后再dfs合并它与父亲的联通信息

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<cstdlib>#define maxn 200005using namespace std;int last[maxn * 2], Next[maxn * 2], edge[maxn * 2], flag[maxn * 2], l = 0, n;int am[maxn * 2],  dp[maxn * 2], sym[maxn];void add(int a, int b, int sym){     edge[l] = b;     Next[l] = last[a];     flag[l] = sym;     last[a] = l;     l++;}void dfs(int pre){     sym[pre] = 1;     for(int i =last[pre]; i != -1; i = Next[i])     if(!sym[edge[i]])     {         dfs(edge[i]);         dp[pre] += dp[edge[i]];         dp[pre] += flag[i];     }     sym[pre] = 0;}void dfs2(int pre, int cnt){     sym[pre] = 1;     for(int i =last[pre]; i != -1; i = Next[i])     if(!sym[edge[i]])     {         int CNT = cnt + (dp[pre] - dp[edge[i]]);         if(flag[i]) CNT--;         else CNT++;         dfs2(edge[i], CNT);     }     dp[pre] += cnt;}int main(){    scanf("%d", &n);    memset(last, -1, sizeof(last));    for(int i = 1; i < n; i++)    {        int a, b;        scanf("%d%d", &a, &b);        add(a, b, 0);        add(b, a, 1);    }    dfs(1);    dfs2(1, 0);    int ans = 99999999;    for(int i = 1; i <= n; i++) ans = min(ans, dp[i]);    printf("%d\n", ans);    for(int i = 1; i <= n; i++) if(dp[i] == ans)printf("%d ", i);    return 0;}
0 0
原创粉丝点击