思路:dp[i]为在以i为根节点的子树中i到各点的需要反向的路的数目。
那么dp[u] = sigma(dp[v] + i) 如果(u,v)是反向边,i=1;反之为0。
这样求出的dp[u]为u到其子树各点的反向边的数目。
在做一遍dfs,使dp[v] = dp[u] + i 如果(u,v)是反向边 ,i=-1;反之,i=1。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 200005;
struct Nod{
int b,flg,next;
void init(int b,int flg,int next){
this->b = b;
this->next = next;
this->flg = flg;
}
}buf[maxn<<1];
int len,E[maxn];
int n,dp[maxn];
void init(){
memset(dp,0,sizeof(dp));
memset(E,-1,sizeof(E));
len = 0;
}
void add_edge(int a,int b){
buf[len].init(b,0,E[a]);E[a]=len++;
buf[len].init(a,1,E[b]);E[b]=len++;
}
void dfs(int u,int pre){
int i,v,flg;
for(i=E[u];i!=-1;i=buf[i].next){
v = buf[i].b;flg = buf[i].flg;
if(v == pre) continue;
dfs(v,u);
dp[u] += dp[v];
if(flg) dp[u] += 1;
}
}
void ndfs(int u,int pre){
int i,flg;
for(i=E[u];i!=-1;i=buf[i].next)
if(buf[i].b==pre){ flg=buf[i].flg;break; }
if(pre != -1){
if(flg) dp[u] = dp[pre] + 1;
else dp[u] = dp[pre] - 1;
}
for(i=E[u];i!=-1;i=buf[i].next)
if(buf[i].b!=pre) ndfs(buf[i].b,u);
}
int main() {
init();
scanf("%d",&n);
int i,j,s,t,o = 0x3f3f3f3f;
for(i=1;i<n;i++){
scanf("%d%d",&s,&t);
add_edge(s,t);
}
dfs(1,-1);ndfs(1,-1);
//for(i=1;i<=n;i++) cout<<dp[i]<<endl;
for(i=1;i<=n;i++) o = min(o,dp[i]);
printf("%d\n",o);
for(i=1,j=0;i<=n;i++){
if(dp[i] == o){
if(j) putchar(' ');j++;
printf("%d",i);
}
}
putchar('\n');
return 0;
}