题目链接:http://codeforces.com/problemset/problem/219/D
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #include<utility> using namespace std; const int maxn = 2*1e5+100; int dp[maxn]; //dp[i]表示以i为根遍历全部的点的最小的权值。 struct Edge{ int u,v,w; int next; Edge(int u=0,int v=0,int w=0,int next=0): u(u), v(v), w(w), next(next) {} }edges[maxn*2]; int head[maxn],cnt; int sum; //以1为根的树至少要修改的边数。 int ans; void addedge(int u,int v){ edges[cnt] = Edge(u,v,0,head[u]); head[u] = cnt++; edges[cnt] = Edge(v,u,1,head[v]); head[v] = cnt++; } void dfs1(int u,int fa){ for(int i=head[u];i!=-1;i=edges[i].next){ Edge& e = edges[i]; if(e.v == fa) continue; sum += e.w; dfs1(e.v,u); } } void dfs2(int u,int fa){ for(int i=head[u];i!=-1;i=edges[i].next){ Edge& e = edges[i]; if(e.v == fa) continue; if(e.w == 1) dp[e.v] = dp[u] - 1; //由于父亲节点的dp[u]已经算出,只需要更新就是了。 else dp[e.v] = dp[u] + 1; ans = min(ans,dp[e.v]); dfs2(e.v,u); } } int main() { //freopen("E:\acm\input.txt","r",stdin); int n; cin>>n; memset(head,-1,sizeof(head)); cnt = 0; for(int i=1;i<n;i++){ int u,v; scanf("%d %d",&u,&v); addedge(u,v); } sum = 0; dfs1(1,-1); memset(dp,0,sizeof(dp)); dp[1] = sum; ans = 0x3f3f3f3f; ans = min(ans,dp[1]); dfs2(1,-1); printf("%d ",ans); for(int i=1;i<=n;i++){ if(dp[i] == ans) printf("%d ",i); } }