题目链接:https://vjudge.net/problem/CodeForces-219D
首先,类似于网上大部分题解所说的,设某一条边正向的weight=0,反向的weight=1,因为反向意味着我们(按DFS方向)走到这条边的时候,就得把这条边翻转,就相当于记一次(w=1)。
然后同样的,
dp[i][0]:表示以i为root的子树中,我们从i出发,要翻转(inverse)多少条边。
dp[i][1]:表示从i往其父亲方向走,要翻转(inverse)多少条边。
那么,最后我们要的,当一个点i为capital时,就要翻转dp[i][0]+dp[i][1]条边。
类似于HDU2196(http://www.cnblogs.com/dilthey/p/7186556.html),我们也要分两次做DFS,第一次做出所有的dp[i][0],第二次做出所有的dp[i][1];
状态转移方程:
对于某个节点u,有子节点(直接相连的)v1~vk,则
dp[u][0] = ( edge[u][v1].w + dp[v1][0] ) + …… + ( edge[u][vk].w + dp[vk][0] )
对于某个节点v,有父亲节点u,则
dp[v][1] = dp[u][1] + ( dp[u][0] - ( edge[u][v].w + dp[v][0] ) ) + ( (edge[u][v].w==1) ? 0 : 1 )
(这个状态转移方程画个图就比较好想,一个节点往上走,可以是它的父亲节点再往上走,也可以是它的父亲节点的其他孩子树,再包括它和它父亲节点相连的那条边)
所以,代码如下:
1 #include<cstdio> 2 #include<vector> 3 #define MAXN 200000+5 4 using namespace std; 5 int n,dp[MAXN][2]; 6 struct Edge{ 7 int u,v,w; 8 }; 9 vector<Edge> adj[MAXN]; 10 void dfs1(int now,int par) 11 { 12 if(adj[now].empty()) 13 { 14 dp[now][0]=0; 15 return; 16 } 17 for(int i=0;i<adj[now].size();i++) 18 { 19 Edge edge=adj[now][i]; 20 int next=edge.v; 21 if(next==par) continue; 22 dfs1(next,now); 23 dp[now][0]+=edge.w+dp[next][0]; 24 } 25 } 26 void dfs2(int now,int par) 27 { 28 if(now==1) dp[now][1]=0; 29 for(int i=0;i<adj[now].size();i++) 30 { 31 Edge edge=adj[now][i]; 32 int next=edge.v; 33 if(next==par) continue; 34 dp[next][1] = dp[now][1] + ( dp[now][0] - (edge.w+dp[next][0]) ) + (edge.w?0:1); 35 dfs2(next,now); 36 } 37 } 38 int main() 39 { 40 scanf("%d",&n); 41 for(int i=1;i<n;i++) 42 { 43 int from,to; 44 scanf("%d%d",&from,&to); 45 adj[from].push_back((Edge){from,to,0}); 46 adj[to].push_back((Edge){to,from,1}); 47 } 48 dfs1(1,0); 49 dfs2(1,0); 50 vector<int> ans; 51 int min=dp[1][0]+dp[1][1]; 52 for(int i=1;i<=n;i++) 53 { 54 if(min>dp[i][0]+dp[i][1]) 55 { 56 min=dp[i][0]+dp[i][1]; 57 ans.clear(); 58 } 59 if(min==dp[i][0]+dp[i][1]) 60 { 61 ans.push_back(i); 62 } 63 } 64 printf("%d ",min); 65 for(int i=0;i<ans.size();i++) 66 { 67 if(i!=0) printf(" "); 68 printf("%d",ans[i]); 69 } 70 printf(" "); 71 }
可以说是第一道大部分都是自己独立完成的树形DP,还是值得庆祝一下的~