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

一个国家,有n座城市,编号为1~n,有n-1条有向边

如果不考虑边的有向性,这n个城市刚好构成一棵树

现在国王要在这n个城市中选择一个作为首都

要求:从首都可以到达这个国家的任何一个城市(边是有向的)

所以一个城市作为首都,可能会有若干边需要改变方向

现在问,选择哪些城市作为首都,需要改变方向的边最少。

输出最少需要改变方向的边数

输出可以作为首都的编号

树形DP

先假定城市1作为首都

令tree(i)表示以i为根的子树

dp[i]表示在tree(i)中,若以i为首都的话,需要改变的边数

第一次dfs,求出dp数组

ans[i]表示在整棵树中,若以i为首都的话,需要改变的边数(注意和dp数组的意义的区别)

明显:ans[1]=dp[1]

明显有:

在一棵有向树中,若首都为u,现在我们要让u的儿子节点v为首都,只需要改变1条边的方向

假设节点u是节点v的父节点,e=(u,v),ans[u]已知

若e的方向指向v,则:ans[v]=ans[u]+1

否则:ans[v]=ans[u]-1

所以第二次dfs,递推求出ans数组

接着,找出min=min(ans[i]),并输出min

输出所有使得ans[i]==min的i

  1 #include<cstdio>
  2 #include<cstring>
  3
  4 using namespace std;
  5
  6 const int maxn=200000+5;
  7
  8 struct Edge
  9 {
 10     int to,next;
 11     bool flag;
 12 };
 13 Edge edge[maxn<<1];
 14 int head[maxn];
 15 int tot;
 16 int ans[maxn];
 17 int dp[maxn];
 18 int print[maxn];
 19
 20 void init()
 21 {
 22     memset(head,-1,sizeof head);
 23     tot=0;
 24     memset(dp,0,sizeof dp);
 25 }
 26
 27 void addedge(int u,int v,bool flag)
 28 {
 29     edge[tot].to=v;
 30     edge[tot].flag=flag;
 31     edge[tot].next=head[u];
 32     head[u]=tot++;
 33 }
 34
 35 void dfs0(int ,int );
 36 void dfs1(int ,int );
 37
 38 int main()
 39 {
 40     int n;
 41     init();
 42     bool cnt=true;
 43     scanf("%d",&n);
 44     for(int i=1;i<n;i++)
 45     {
 46         int u,v;
 47         scanf("%d %d",&u,&v);
 48         addedge(u,v,cnt);
 49         addedge(v,u,!cnt);
 50     }
 51     dfs0(1,-1);
 52     ans[1]=dp[1];
 53     dfs1(1,-1);
 54
 55     int min=ans[1];
 56     for(int i=2;i<=n;i++)
 57     {
 58         if(ans[i]<min)
 59             min=ans[i];
 60     }
 61     tot=1;
 62     for(int i=1;i<=n;i++)
 63     {
 64         if(ans[i]==min)
 65         {
 66             print[tot++]=i;
 67         }
 68     }
 69
 70     printf("%d\n",min);
 71     for(int i=1;i<tot-1;i++)
 72     {
 73         printf("%d ",print[i]);
 74     }
 75     printf("%d\n",print[tot-1]);
 76
 77     return 0;
 78 }
 79
 80 void dfs0(int u,int pre)
 81 {
 82     for(int i=head[u];~i;i=edge[i].next)
 83     {
 84         int v=edge[i].to;
 85         bool flag=edge[i].flag;
 86         if(v==pre)
 87             continue;
 88         dfs0(v,u);
 89         if(flag)
 90             dp[u]+=dp[v];
 91         else
 92             dp[u]+=(dp[v]+1);
 93     }
 94     return ;
 95 }
 96
 97 void dfs1(int u,int pre)
 98 {
 99     for(int i=head[u];~i;i=edge[i].next)
100     {
101         int v=edge[i].to;
102         int flag=edge[i].flag;
103         if(v==pre)
104             continue;
105         if(flag)
106             ans[v]=ans[u]+1;
107         else
108             ans[v]=ans[u]-1;
109         dfs1(v,u);
110     }
111     return ;
112 }

时间: 2024-12-15 04:49:59

CF 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

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)

题目链接: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 Choosing Capital for Treeland(树形DP)

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

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 #includ

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