poj 1655 Balancing Act 求树的重心【树形dp】

poj 1655 Balancing Act

题意:求树的重心且编号数最小

一棵树的重心是指一个结点u,去掉它后剩下的子树结点数最少。

(图片来源: PatrickZhou 感谢博主)

看上面的图就好明白了,不仅要考虑当前结点子树的大小,也要“向上”考虑树的大小。

那么其它就dfs完成就行了,son[] 存以前结点为根的结点个数。

这是用邻接表写:

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn = 20006;
 7 const int INF = 1 << 30;
 8 int head[maxn];
 9 int son[maxn];
10 bool vis[maxn];
11 int n,siz, cnt, num;
12 struct Edge
13 {
14     int to, next;
15 };
16 Edge edge[maxn*2];
17 
18 void Init()
19 {
20     memset(vis, 0, sizeof(vis));
21     memset(head, -1, sizeof(head));
22     siz =num= INF;
23     cnt = 0;
24 }
25 
26 
27 void add(int u, int v)
28 {
29     edge[cnt].to = v;
30     edge[cnt].next = head[u];
31     head[u] = cnt++;
32 }
33 
34 void dfs(int u)
35 {
36     vis[u] = 1;
37     son[u] = 1;
38     int tmp = 0;
39     for (int i = head[u]; i != -1; i = edge[i].next)
40     {
41         int v = edge[i].to;
42         if (!vis[v]) {
43             dfs(v);
44             son[u] += son[v];
45             tmp = max(tmp, son[v]);
46         }
47     }
48     tmp = max(tmp, n - son[u]);
49     if (tmp < siz || (tmp == siz&&u < num)) {
50         siz = tmp;
51         num = u;
52     }
53 }
54 
55 int main()
56 {
57     int T;
58     cin >> T;
59     while (T--)
60     {
61         cin >> n;
62         Init();
63         for (int i = 1; i < n; i++) {
64             int u, v;
65             cin >> u >> v;
66             add(u, v);
67             add(v, u);
68         }
69         dfs(1);
70         cout << num << " " << siz << endl;
71     }
72     return 0;
73 }

 

这题用stl不超时:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<vector>
 5 #include<algorithm>
 6 using namespace std;
 7 const int maxn = 20006;
 8 const int INF = 1 << 30;
 9 vector<int> tree[maxn];
10 int son[maxn];
11 int n, siz,num;
12 
13 void dfs(int u, int fa)
14 {
15     son[u] = 1;
16     int tmp = 0;
17     for (int i = 0; i < tree[u].size(); i++) {
18         int v = tree[u][i];
19         if (v != fa) {
20             dfs(v,u);
21             son[u] += son[v];
22             tmp = max(tmp, son[v]);
23         }
24     }
25     tmp = max(tmp, n - son[u]);
26     if ((tmp < siz) || (tmp == siz&&u > num)) {
27         siz = tmp;
28         num = u;
29     }
30 }
31 
32 int main()
33 {
34     int T;
35     cin >> T;
36     while (T--)
37     {
38         cin >> n;
39         for (int i = 0; i <= n; i++) tree[i].clear();
40         for (int i = 1; i < n; i++) {
41             int u, v;
42             cin >> u >> v;
43             tree[u].push_back(v);
44             tree[v].push_back(u);
45         }
46         num = 0, siz = INF;
47         dfs(1, -1);
48         cout << num << " " << siz << endl;
49     }
50     return 0;
51 }

 

转载于:https://www.cnblogs.com/zxhyxiao/p/7784372.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值