题意是:给定n个点,n-1条有向边。求 使该点到全部点改变边方向最少,并输出那些点。ios
题解:正向边权值为0,反向为1.ide
第一次dfs记录每一个点到全部子树中须要改变的边的条数。 (自下向上推)(优化下只需求出根节点到全部的点须要改变的边的条数)优化
第二次dfs由父节点求子节点到全部点的须要改变的边的条数。(自上向下)spa
1 #include<cstdio> 2 #include<cstring> 3 #include<string> 4 #include<iostream> 5 #include<vector> 6 using namespace std; 7 const int N=200020; 8 struct Point 9 { 10 int v,w; 11 }; 12 vector<Point>V[N]; 13 int vis[N],dp[N]; 14 void init(int n) 15 { 16 for(int i=1;i<n;i++) 17 { 18 V[i].clear(); 19 vis[i]=0; 20 dp[i]=0; 21 } 22 } 23 int res=0; 24 void dfs1(int s) //求根节点到全部点须要改变的边的条数. 25 { 26 vis[s]=1; 27 for(int i=0;i<(int)V[s].size();i++) 28 { 29 int x=V[s][i].v; 30 int w=V[s][i].w; 31 if(!vis[x]) 32 { 33 dfs1(x); 34 res+=w; 35 } 36 } 37 } 38 void dfs2(int s) //第二次dfs,求节点到全部的点须要改变的边的条数。 39 { 40 vis[s]=1; 41 for(int i=0;i<(int)V[s].size();i++) 42 { 43 int x=V[s][i].v; 44 int w=V[s][i].w; 45 if(!vis[x]) //s为父节点,x为节点。 46 { 47 if(w==0) 48 { 49 dp[x]=dp[s]+1; // s指向x。 50 } 51 else dp[x]=dp[s]-1; //x指向s; 52 dfs2(x); 53 } 54 } 55 } 56 int main() 57 { 58 //freopen("Input.txt","r",stdin); 59 int n,i; 60 while(~scanf("%d",&n)) 61 { 62 init(n); 63 int a,b; 64 Point tmp; 65 for(i=1;i<n;i++) 66 { 67 scanf("%d%d",&a,&b); 68 tmp.v=b;tmp.w=0; //正向边 69 V[a].push_back(tmp); 70 tmp.v=a;tmp.w=1; //反向边。 71 V[b].push_back(tmp); 72 } 73 res=0; 74 dfs1(1); 75 // for(i=1;i<=n;i++) 76 // printf("%d \n",dp[i]); 77 memset(vis,0,sizeof(vis)); 78 dp[1]=res; 79 dfs2(1); 80 int Min=0x7fffffff; 81 int j; 82 for(i=1;i<=n;i++) 83 { 84 if(Min>=dp[i]) { Min=dp[i];j=i;} 85 //printf("%d ---> %d \n",i,dp[i]); 86 } 87 printf("%d\n",Min); 88 for(i=1;i<=n;i++) 89 { 90 if(i==j) 91 { 92 printf("%d\n",i); 93 break; 94 } 95 if(dp[i]==Min) 96 printf("%d ",i); 97 } 98 } 99 return 0; 100 }