題意是:給定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 }