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 }