cf219D. Choosing Capital for Treeland (树形dp)

题意

cf219d
一棵n个点n-1条有向边的树,求翻转最少的边,使这些个点都联通,问这样的点,从小到大输出


题解

既然要求翻转的最少,那我们可以给正向的边权值为0,反向的权值为1。这样以每个点为根时,整棵树的值就是需要翻转的边数


代码

#include <cstdio>
#include <algorithm>
using namespace std;
#define N 220000
int ans[N],d[N],h[N],n,num=0,data[N],tot=0,mn=N;
struct node{int x,y,z,next;}mp[N<<1];
void insert(int x,int y){
    mp[++num].x=x;mp[num].y=y;mp[num].z=0;mp[num].next=h[x];h[x]=num;
    mp[++num].x=y;mp[num].y=x;mp[num].z=1;mp[num].next=h[y];h[y]=num;
}
void dfs1(int u){
    ans[u]=0;
    for(int i=h[u];i;i=mp[i].next){
        int v=mp[i].y;if(d[v]) continue;
        d[v]=d[u]+1;dfs1(v);ans[u]+=ans[v]+mp[i].z; 
    }
}
void dfs2(int u){
    if(ans[u]<mn) mn=ans[u],tot=0,data[++tot]=u;
    else if(ans[u]==mn) data[++tot]=u;
    for(int i=h[u];i;i=mp[i].next){
        int v=mp[i].y;if(d[v]!=d[u]+1) continue;
        ans[v]=ans[u];
        if(mp[i].z) ans[v]--;else ans[v]++;
        dfs2(v); 
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        int x,y;scanf("%d%d",&x,&y);
        insert(x,y);
    }d[1]=1;dfs1(1);dfs2(1);sort(data+1,data+tot+1);
    printf("%d\n",mn);
    for(int i=1;i<=tot;i++) printf("%d ",data[i]);
    return 0;
} 

猜你喜欢

转载自blog.csdn.net/sunshiness_s/article/details/79790686