树形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 namespace std;
11 
12 const int MAXN = 2e5 + 10;
13 const int INF = 0x3f3f3f3f;
14 struct Edge    {
15     int v, w;
16 };
17 vector<Edge> G[MAXN];
18 int dp[MAXN];
19 bool vis[MAXN];
20 int n, res;
21 
22 void DFS(int u)    {
23     vis[u] = true;
24     for (int i=0; i<G[u].size (); ++i)    {
25         int v = G[u][i].v, w = G[u][i].w;
26         if (vis[v])    continue;
27         DFS (v);
28         res += w;
29     }
30 }
31 
32 void DFS2(int u)    {
33     vis[u] = true;
34     for (int i=0; i<G[u].size (); ++i)    {
35         int v = G[u][i].v, w = G[u][i].w;
36         if (vis[v])    continue;
37         if (w == 0)    dp[v] = dp[u] + 1;
38         else    dp[v] = dp[u] - 1;
39         DFS2 (v);
40     }
41 }
42 
43 void work(void)    {
44     memset (vis, false, sizeof (vis));
45     memset (dp, 0, sizeof (dp));
46 
47     res = 0;    DFS (1);    dp[1] = res;
48     memset (vis, false, sizeof (vis));
49     DFS2 (1);
50 
51     int mn = INF, p = 0;
52     for (int i=1; i<=n; ++i)    {
53         if (mn >= dp[i])    {
54             mn = dp[i];    p = i;
55         }
56     }
57     printf ("%d\n", mn);
58     for (int i=1; i<=n; ++i)    {
59         if (i == p)    {
60             printf ("%d\n", i);    break;
61         }
62         if (dp[i] == mn)    printf ("%d ", i);
63     }
64 }
65 
66 int main(void)    {        //Codeforces Round #135 (Div. 2) D. Choosing Capital for Treeland
67 //    freopen ("A.in", "r", stdin);
68 
69     while (scanf ("%d", &n) == 1)    {
70         for (int i=1; i<=n; ++i)    G[i].clear ();
71         for (int i=1; i<=n-1; ++i)    {
72             int u, v;    scanf ("%d%d", &u, &v);
73             G[u].push_back ((Edge) {v, 0});
74             G[v].push_back ((Edge) {u, 1});
75         }
76 
77         work ();
78     }
79 
80     return 0;
81 }

 

转载于:https://www.cnblogs.com/Running-Time/p/4663538.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值