码迷,mamicode.com
首页 > Windows程序 > 详细

Codeforces 219D Choosing Capital for Treeland:Tree dp

时间:2018-01-10 11:28:20      阅读:233      评论:0      收藏:0      [点我收藏+]

标签:bool   题目   cout   ack   als   define   string   转移   namespace   

题目链接:http://codeforces.com/problemset/problem/219/D

题意:

  给你一棵树,n个节点。

  树上的边都是有向边,并且不一定是从父亲指向儿子的。

  你可以任意翻转一些边的方向。

  现在让你找一个节点,使得从这个节点出发能够到达其他所有节点,并保证翻转边的数量最小。

  问你最少翻转多少条边,并输出所有满足此条件的节点编号。

 

题解:

  本题要解两个dp: dp1 & dp2

  首先考虑dp1:

    表示状态:

      dp1[i]表示使节点i能够到达i的子树中的所有节点,翻转边的最小数量。

    如何转移:

      dp1[i] = ∑ (dp1[son] + 边<i,son>由i指向son ? 0 : 1)

      dfs一遍即可。

  然后求dp2:

    表示状态:

      dp2[i]表示使节点i能够到达这棵树的所有节点,翻转边的最小数量。

    如何转移:

      dp2[i] = dp2[par] + 边<par,i>是否由par指向i ? 1 : -1

      如果边<par,i>由par指向i,那么在dp2[par]中这条边是不会被翻转的,所以此时应该将它翻转,代价+1。

      如果边<par,i>由i指向par,那么在dp2[par]中这条边已经被翻转了一次,然而在dp2[i]中是不需要翻转的,所以将dp2[par]中多余的那次翻转减掉就好。

    边界条件:

      dp2[1] = dp1[1]

      (默认根节点为1)

 

  所以最终答案为dp2[i]中的最小值,然后将所有dp2[i]等于ans的节点输出就好啦。

 

AC Code:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <vector>
 5 #define MAX_N 200005
 6 #define INF 1000000000
 7 
 8 using namespace std;
 9 
10 struct Edge
11 {
12     int dest;
13     bool flag;
14     Edge(int _dest,bool _flag)
15     {
16         dest=_dest;
17         flag=_flag;
18     }
19     Edge(){}
20 };
21 
22 int n;
23 int ans=INF;
24 int dp1[MAX_N];
25 int dp2[MAX_N];
26 vector<Edge> edge[MAX_N];
27 
28 void read()
29 {
30     cin>>n;
31     int x,y;
32     for(int i=1;i<n;i++)
33     {
34         cin>>x>>y;
35         edge[x].push_back(Edge(y,true));
36         edge[y].push_back(Edge(x,false));
37     }
38 }
39 
40 void dfs1(int now,int p)
41 {
42     dp1[now]=0;
43     for(int i=0;i<edge[now].size();i++)
44     {
45         Edge temp=edge[now][i];
46         if(temp.dest!=p)
47         {
48             dfs1(temp.dest,now);
49             dp1[now]+=dp1[temp.dest]+(!temp.flag);
50         }
51     }
52 }
53 
54 void dfs2(int now,int p,bool d)
55 {
56     if(now==1) dp2[now]=dp1[now];
57     else dp2[now]=dp2[p]+(d?1:-1);
58     ans=min(ans,dp2[now]);
59     for(int i=0;i<edge[now].size();i++)
60     {
61         Edge temp=edge[now][i];
62         if(temp.dest!=p) dfs2(temp.dest,now,temp.flag);
63     }
64 }
65 
66 void work()
67 {
68     dfs1(1,-1);
69     dfs2(1,-1,233);
70     cout<<ans<<endl;
71     for(int i=1;i<=n;i++)
72     {
73         if(dp2[i]==ans) cout<<i<<" ";
74     }
75     cout<<endl;
76 }
77 
78 int main()
79 {
80     read();
81     work();
82 }

 

Codeforces 219D Choosing Capital for Treeland:Tree dp

标签:bool   题目   cout   ack   als   define   string   转移   namespace   

原文地址:https://www.cnblogs.com/Leohh/p/8256852.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!