cf 219D

树形dp;

思想: 把正向边赋值为0;反向边赋值为1;然后求出点到其他点的最小距离;

两次dfs:

第一次是从下往上:记录每个点到所有子树中需要改变的边的条数;

第二次是自上往下:由父节点求子节点到所有点的需要改变的边的条数。

代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<vector>
 4 #define maxn 200005
 5 using namespace std;
 6 
 7 struct node
 8 {
 9     int v,w;
10 };
11 
12 vector<node>ve[maxn];
13 int dp[maxn],res;
14 bool vis[maxn];
15 
16 void dfs1(int a)
17 {
18     vis[a]=1;
19     int l=ve[a].size();
20     for(int i=0;i<l;i++)
21     {
22         int k=ve[a][i].v;
23         if(vis[k])continue;
24         dfs1(k);
25         res+=ve[a][i].w;
26     }
27 }
28 
29 void dfs2(int f)
30 {
31     vis[f]=1;
32     int l=ve[f].size();
33     for(int i=0;i<l;i++)
34     {
35         int k=ve[f][i].v;
36         if(vis[k])continue;
37         if(ve[f][i].w==0) dp[k]=dp[f]+1;
38         else dp[k]=dp[f]-1;
39         dfs2(k);
40     }
41 }
42 
43 int main()
44 {
45     int n,a,b;
46     node no;
47     scanf("%d",&n);
48     for(int i=1;i<n;i++)
49     {
50         scanf("%d%d",&a,&b);
51         no.v=b,no.w=0;
52         ve[a].push_back(no);
53         no.v=a,no.w=1;
54         ve[b].push_back(no);
55     }
56     res=0;
57     dfs1(1);
58     dp[1]=res;
59     memset(vis,0,sizeof vis);
60     dfs2(1);
61     int min=999999999;
62     for(int i=1;i<=n;i++)
63         if(min>dp[i]) min=dp[i];
64     printf("%d\n",min);
65     for(int i=1;i<=n;i++)
66         if(min==dp[i]) printf("%d ",i);
67     puts("");
68     return 0;
69 }
View Code

 

posted @ 2013-09-17 17:21  Yours1103  阅读(531)  评论(0编辑  收藏  举报