Codeforces 219 D Choosing Capital for Treeland

题意:给定一个树形图,现在选择其中一个节点,为了从此节点到达所有的其他节点需要改变一些边的方向,求出最小需要修改的边数以及满足最优解的节点。。

解法:树形dp,第一次随意指定一个点为根,然后根据子节点的信息更新父节点,dp[i][0]表示使得i节点能到达它所有子节点需要修改的边数。

  第二次dp,根据第一次dp的结果,利用父节点的信息来更新子节点,dp[i][2]表示使得i节点到达其他所有节点需要修改的边数。

  如果pre[i]指向i,那么dp[i][1]=dp[pre[i]][0]-1;

  如果i指向pre[i],那么dp[i][1]=dp[pre[i]][0]+1;

 1 #include<iostream>
 2 #include<cstring>
 3 #include<vector>
 4 #include<algorithm>
 5 #define N 200010
 6 using namespace std;
 7 struct Edge{
 8     int next,val;
 9 };
10 vector<Edge>V[N];
11 int dp[N][2];
12 void dfs1(int u,int pre){
13     dp[u][0]=0;
14     for(int i=0;i<V[u].size();i++){
15         int son=V[u][i].next;
16         if(son==pre)continue;
17         dfs1(son,u);
18         dp[u][0]+=(dp[son][0]+V[u][i].val);
19     }
20 }
21 void dfs2(int u,int pre,int c){
22     if(u==pre){
23         dp[u][1]=dp[u][0];
24     }
25     else {
26         if(V[pre][c].val==1)dp[u][1]=dp[pre][1]-1;
27         else dp[u][1]=dp[pre][1]+1;
28     }
29 
30     for(int i=0;i<V[u].size();i++){
31         int son=V[u][i].next;
32         if(son==pre)continue;
33         dfs2(son,u,i);
34     }
35 }
36 int main(){
37     int n;
38     while(cin>>n){
39         for(int i=1;i<=n;i++)V[i].clear();
40         for(int i=1;i<n;i++){
41             int a,b;
42             cin>>a>>b;
43             Edge E;
44             E.next=b;E.val=0;
45             V[a].push_back(E);
46             E.next=a;E.val=1;
47             V[b].push_back(E);
48         }
49         dfs1(1,1);
50         dfs2(1,1,0);
51         int minn=(1<<30);
52         for(int i=1;i<=n;i++)
53             minn=min(dp[i][1],minn);
54         cout<<minn<<endl;
55         for(int i=1;i<=n;i++)
56             if(dp[i][1]==minn)
57                 cout<<i<<" ";
58         cout<<endl;
59     }
60     return 0;
61 }
posted @ 2012-11-06 17:32  silver__bullet  阅读(583)  评论(0编辑  收藏  举报