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 }
时间: 2024-10-11 12:33:27

poj 1655 Balancing Act 求树的重心【树形dp】的相关文章

POJ 1655 Balancing Act(求树的重心--树形DP)

题意:求树的重心的编号以及重心删除后得到的最大子树的节点个数size,如果size相同就选取编号最小的. 思路:随便选一个点把无根图转化成有根图,dfs一遍即可dp出答案 //1348K 125MS C++ 1127B #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<vector> using namespace std; int

POJ 1655 Balancing Act(求树的重心)

题目大意: 就是要求树的重心,重心的定义就是删除这个点使得森林尽量平衡. 也可以让分治子树的时候使得每颗子树的数量在nlogn以内. 思路分析: son [x] 表示x的子树的数量  不包括自己. balance 表示最大的森林的节点数. 最后我们要让最大的balance 最小. balance = max (balance ,n - 1 - son[x]  , son[j] +1).. #include <cstdio> #include <iostream> #include

poj 1655 Balancing Act 【树的重心】

知识点:树的重心 定义:以这个点为根,那么所有的子树(不算整个树自身)的大小都不超过整个树大小的一半. 性质: 性质 1 :树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个距离和,他们的距离和一样. 性质 2 :把两棵树通过某一点相连得到一颗新的树,新的树的重心必然在连接原来两棵树重心的路径上. 性质 3 :一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置. 题目:poj 1655 Balancing Act 题意:给出一颗树,求树的重心点以及重心点删除后中的最大子树.

POJ 1655 Balancing Act(树的重心)

Balancing Act Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14062   Accepted: 5937 Description Consider a tree T with N (1 <= N <= 20,000) nodes numbered 1...N. Deleting any node from the tree yields a forest: a collection of one or m

POJ 1655 Balancing Act (树的重心,常规)

题意:求树的重心,若有多个重心,则输出编号较小者,及其子树中节点最多的数量. 思路: 树的重心:指的是一个点v,在删除点v后,其子树的节点数分别为:u1,u2....,设max(v)为其中的最大值,点v的max(v)是所有点里面最小的,称v为树的重心. 如何求任一重心?按树形来看,max(v)可以由其父亲贡献,也可以由其任一孩子贡献.孩子比较好解决,不就是深搜一遍,然后回溯时统计下数量就行了?而父亲的怎么办?可以知道,点v到其父亲这一叉就是n-sum(v)了,sum(v)指的是以v为根的子树的节

POJ 1655 Balancing Act (树的重心)

题意:求树的重心裸题. 拓展:树的重心可以在树分治时避免退化链时的最坏时间复杂度,提高时间效率. #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<queue&g

POJ 1655 BalanceAct 3107 Godfather (树的重心)(树形DP)

参考网址:http://blog.csdn.net/acdreamers/article/details/16905653 树的重心的定义: 树的重心也叫树的质心.找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡. 通常利用树形DP找重心: BalanceAct: http://poj.org/problem?id=1655 题意:给定一棵树,求树的重心的编号以及重心删除后得到的最大子树的节点个数size,如果size相同就选取编号最

POJ 1655 Balancing Act【树的重心】

Balancing Act Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14251   Accepted: 6027 Description Consider a tree T with N (1 <= N <= 20,000) nodes numbered 1...N. Deleting any node from the tree yields a forest: a collection of one or m

poj1655 Balancing Act 求树的重心

http://poj.org/problem?id=1655 Balancing Act Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9072   Accepted: 3765 Description Consider a tree T with N (1 <= N <= 20,000) nodes numbered 1...N. Deleting any node from the tree yields a fo