cf 219D
树形dp;
思想: 把正向边赋值为0;反向边赋值为1;然后求出点到其他点的最小距离;
两次dfs:
第一次是从下往上:记录每个点到所有子树中需要改变的边的条数;
第二次是自上往下:由父节点求子节点到所有点的需要改变的边的条数。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #define maxn 200005 5 using namespace std; 6 7 struct node 8 { 9 int v,w; 10 }; 11 12 vector<node>ve[maxn]; 13 int dp[maxn],res; 14 bool vis[maxn]; 15 16 void dfs1(int a) 17 { 18 vis[a]=1; 19 int l=ve[a].size(); 20 for(int i=0;i<l;i++) 21 { 22 int k=ve[a][i].v; 23 if(vis[k])continue; 24 dfs1(k); 25 res+=ve[a][i].w; 26 } 27 } 28 29 void dfs2(int f) 30 { 31 vis[f]=1; 32 int l=ve[f].size(); 33 for(int i=0;i<l;i++) 34 { 35 int k=ve[f][i].v; 36 if(vis[k])continue; 37 if(ve[f][i].w==0) dp[k]=dp[f]+1; 38 else dp[k]=dp[f]-1; 39 dfs2(k); 40 } 41 } 42 43 int main() 44 { 45 int n,a,b; 46 node no; 47 scanf("%d",&n); 48 for(int i=1;i<n;i++) 49 { 50 scanf("%d%d",&a,&b); 51 no.v=b,no.w=0; 52 ve[a].push_back(no); 53 no.v=a,no.w=1; 54 ve[b].push_back(no); 55 } 56 res=0; 57 dfs1(1); 58 dp[1]=res; 59 memset(vis,0,sizeof vis); 60 dfs2(1); 61 int min=999999999; 62 for(int i=1;i<=n;i++) 63 if(min>dp[i]) min=dp[i]; 64 printf("%d\n",min); 65 for(int i=1;i<=n;i++) 66 if(min==dp[i]) printf("%d ",i); 67 puts(""); 68 return 0; 69 }