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

题意:给一个树形图,n个节点,n-1条有向边,要求选一个节点作为根,使需要改变方向的边的数目最少。并输出所有可能作为根的点。

思路:

  先随便一个点进行DFS,计算将每棵子树的边全部往下时,所需要的费用down[i]。还是那个点进行DFS,这次就要求答案了,尝试将每个点t作为根,那么以t作为根的总费用=down[t]+父亲这棵子树。down[t]已经在第一次DFS中求出,而父亲这棵子树就不是down[父亲]了,而是down[父亲]-down[t]+w(父亲,t)。注:w为边权。

 1 #include <bits/stdc++.h>
 2 #define pii pair<int,int>
 3 #define INF 0x3f3f3f3f
 4 #define LL long long
 5 using namespace std;
 6 const int N=2e5+10;
 7
 8 struct node
 9 {
10     int from,to,rev,next;
11     node(){};
12     node(int from,int to,int rev,int next):from(from),to(to),rev(rev),next(next){};
13 }edge[N*2];
14 int head[N],  n, edge_cnt;
15 void add_node(int from,int to,int rev)
16 {
17     edge[edge_cnt]=node(from,to,rev,head[from]);
18     head[from]=edge_cnt++;
19 }
20
21 int down[N];     //down[i]表示是往下到点i
22 void DFS(int t,int far)
23 {
24     node e;
25     for(int i=head[t]; i!=-1; i=e.next)     //递归先算子树的
26     {
27         e=edge[i];
28         if(e.to^far)    DFS(e.to, t);
29     }
30     int sum=0;
31     for(int i=head[t]; i!=-1; i=e.next)     //再算自己的
32     {
33         e=edge[i];
34         if(e.to^far)    sum+=down[e.to]+e.rev;
35     }
36     down[t]=sum;   //只有1种情况:所有子树全部向下
37 }
38
39 int ans[N], big;
40 void DFS2(int t,int far,int val)
41 {
42     node e;
43     ans[t]=down[t]+val;     //以本节点为根
44     big=min(big, ans[t]);
45     for(int i=head[t]; i!=-1; i=e.next)
46     {
47         e=edge[i];
48         if(e.to^far)
49         {
50             int r=ans[t]-down[e.to]-e.rev+(e.rev^1);
51             DFS2(e.to, t, r);
52         }
53     }
54 }
55
56 void init()
57 {
58     memset(head, -1, sizeof(head));
59     memset(down, 0x3f, sizeof(down));
60     edge_cnt=0;
61     big=INF;
62 }
63
64 int main()
65 {
66     //freopen("input.txt", "r", stdin);
67     init();
68     scanf("%d",&n);
69     for(int i=1,a,b; i<n; i++)
70     {
71         scanf("%d%d",&a,&b);
72         add_node(a,b,0);    //正向
73         add_node(b,a,1);
74     }
75     DFS(1,-1);
76     DFS2(1,-1,0);
77     printf("%d\n",big);
78     for(int i=1; i<=n; i++) //输出解
79         if(big==ans[i])
80             printf("%d ",i);
81     return 0;
82 }

AC代码

时间: 2024-08-27 05:21:26

CodeForces 219D Choosing Capital for Treeland (树形DP)的相关文章

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

题目链接: http://codeforces.com/contest/219/problem/D 题意: 给一个n节点的有向无环图,要找一个这样的点:该点到其它n-1要逆转的道路最少,(边<u,v>,如果v要到u去,则要逆转该边方向)如果有多个这样的点,则升序输出所有 思路: 看了三篇博客,挺好的 http://blog.csdn.net/chl_3205/article/details/9284747 http://m.blog.csdn.net/qq_32570675/article/d

CF 219D Choosing Capital for Treeland 树形DP 好题

一个国家,有n座城市,编号为1~n,有n-1条有向边 如果不考虑边的有向性,这n个城市刚好构成一棵树 现在国王要在这n个城市中选择一个作为首都 要求:从首都可以到达这个国家的任何一个城市(边是有向的) 所以一个城市作为首都,可能会有若干边需要改变方向 现在问,选择哪些城市作为首都,需要改变方向的边最少. 输出最少需要改变方向的边数 输出可以作为首都的编号 树形DP 先假定城市1作为首都 令tree(i)表示以i为根的子树 dp[i]表示在tree(i)中,若以i为首都的话,需要改变的边数 第一次

Codeforces 219D. Choosing Capital for Treeland (树dp)

题目链接:http://codeforces.com/contest/219/problem/D 树dp 1 //#pragma comment(linker, "/STACK:102400000, 102400000") 2 #include <algorithm> 3 #include <iostream> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cstdio&

(纪念第一道完全自己想的树DP)CodeForces 219D Choosing Capital for Treeland

Choosing Capital for Treeland time limit per test 3 seconds memory limit per test 256 megabytes input standard input output standard output The country Treeland consists of n cities, some pairs of them are connected with unidirectional roads. Overall

codeforces 219D D. Choosing Capital for Treeland(树形dp)

题目连接: codeforces 219D 题目大意: 给出一棵树,但是它的边是有向边,选择一个城市,问最少调整多少条边的方向能使一个选中城市可以到达所有的点,输出最小的调整的边数,和对应的点. 题目分析: 定义dp[u]为以u为根的子树中要使根都可达,需要调换方向的边的条数. 定义dir[v]记录点v到父亲节点的边的方向. 然后就是将每个点提成根的操作了. dp[u]换成新的定义,以u为根的到达整棵树需要调整的边的条数. dp[u] = dp[p] + dir[u]?1:-1 详情见代码,这道

Codeforces 219D Choosing Capital for Treeland(树形DP)

题目是给一张边有向的树形图.要选出首都的点,首都要都能走到其他点,因此要反转一些边的方向.问可以选哪几个点作为首都,使它们所需反转边的数量最少. 这题挺好想的,因为做过HDU2196. 首先就不妨设正向边权值为0,反向边权值为1,那样就是各个点出发到其他点经过边所需的最少权值和. 然后对于每个点,分两个部分考虑:以这个点为根的子树.这个点往上走的部分: dp[0][u]表示以u点作为首都且以u点为根的子树部分所需反转边的数量,容易知道就等于子树内边权和 dp[1][u]表示以u点作为首都且u点向

Codeforces 219D Choosing Capital for Treeland 2次DP

//选择一个根使得变换最少边的方向使得能够到达所有点#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #i

codeforces:219D. Choosing Capital for Treeland

题目大意:国家由n个城市以及n-1条连接不同城市的道路组成(每条道路都有正向和逆向之分),并且每个城市到另外一个城市都至少存在一条路径.现在议会要决定选一个城市作为首都.当一个城市选为首都时,需要将所有从首都到其它城市的路径上的所有边都是正向的(如果不是正向的则需要颠转道路).求这样的首都,使得需要颠转的道路数目最小. 其中2<=n<=2e5. 首先这显然是一副无向无环连通图(参考我的博客连通图的一些性质).因此从任意一个城市出发到另外一个城市都有唯一一条路径. 为了后面分析的简便,这里记选取

树形DP Codeforces Round #135 (Div. 2) D. Choosing Capital for Treeland

题目传送门 1 /* 2 题意:求一个点为根节点,使得到其他所有点的距离最短,是有向边,反向的距离+1 3 树形DP:首先假设1为根节点,自下而上计算dp[1](根节点到其他点的距离),然后再从1开始,自上而下计算dp[v], 4 此时可以从上个节点的信息递推出来 5 */ 6 #include <cstdio> 7 #include <cstring> 8 #include <cmath> 9 #include <vector> 10 using name