POJ 1655 Balancing Act (求树的重心)【树形DP】(经典)

<题目链接>

题目大意:
给你一棵树,任意去除某一个点后,树被分成了几个联通块,则该点的平衡值为所有分成的连通块中,点数最大的那个,问你:该树所有点中,平衡值最小的那个点是什么?

解题分析:

运用DFS,找到以u为根节点,所有子节点数的最大值,然后求出这些最大值的最小值。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6 const int MAXN = 2e4+7;
 7 struct Edge{
 8     int to,next;
 9 }edge[MAXN*2];         //注意这里要*2,因为要存双向边
10 
11 int head[MAXN],tot;
12 void init(){
13     memset(head,-1,sizeof(head));
14     tot = 0;
15 }
16 void addedge(int u,int v){
17     edge[tot].to = v;edge[tot].next = head[u];
18     head[u] = tot++;
19 }
20 int dp[MAXN],num[MAXN];
21 int n;
22 
23 void dfs(int u,int pre){
24     dp[u] = 0;num[u] = 1;
25     for(int i = head[u];i != -1;i = edge[i].next){
26         int v = edge[i].to;
27         if(v == pre)continue;        //如果下一个点是u的父亲(即刚刚走过的点),那么跳过,防止下一步dfs(v,u)遍历该无向图时,不停的在两个点之间来回遍历
28         dfs(v,u);          //继续从它的子节点开始向下搜索 
29         dp[u] = max(dp[u],num[v]);   //dp[u]指的是u的每个子节点方向所对应的最大节点数的最大值 
30         num[u] += num[v];           
31     }
32     //num[u]此时代表除父节点方向外的所有子节点数(包括它本身,,因为num[u]初始化为1)
33     dp[u] = max(dp[u],n - num[u]);     //n-num[u]指的是dp[u]父节点方向的节点数
34 }
35 
36 int main(){
37     int T;scanf("%d",&T);
38     int u,v;
39     while(T--){
40         scanf("%d",&n);
41         init();
42         for(int i = 1;i < n;i++){
43             scanf("%d%d",&u,&v);
44             addedge(u,v);addedge(v,u);
45         }
46         dfs(1,-1);
47         int loc=-1,ans=1e9;
48         for(int i=1;i<=n;i++){
49             if(ans>dp[i])
50                 ans=dp[i],loc=i;
51         }
52         printf("%d %d\n",loc,ans);
53     }
54     return 0;
55 }

 

 

 

2018-08-17

posted @ 2018-08-17 10:12  悠悠呦~  阅读(205)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end