CodeForces 219D Choosing Capital for Treeland (树形dp)

题意是:给定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 }
View Code
相关文章
相关标签/搜索