和树的最大独立问题类似,先任选一个结点作为根节点,把无根树变成有根树,然后设d(i)表示以i为根的子树的结点的个数。不难发现d(i)=∑d(j)+1,j∈s(i)。s(i)为i结点的所有儿子结点的编号的集合。程序也十分简单:只需要DFS一次,在无根树有根数的同时计算即可,连记忆化都不需要——因为本来就没有重复计算。
那么,删除结点i后,最大的连通块有多少个呢?结点i的子树中最大有max{d(j)}个结点,i的“上方子树”中有n-d(i)个结点,

代码调试帮助理解:

scanf:

6

1 2
2 3
2 4
4 5

5 6

printf:2 4

/**********
代码调试
**********/
#include <cstdio>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <cstring>
#include <utility>
#include <string>
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
#define eps 1e-10
#define inf 0x3f3f3f3f
#define ll long long
#define CL(a,b) memset(a,b,sizeof(a))
#define MAXN 100010
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 5e4 + 5;
vector<int>G[maxn];
int ans, n;
int dp[maxn],tot,num[maxn];void init(){ans=INF;CL(dp,0);
}
void dfs(int u, int fa) {  //递归转化以u为根的子树,u的父亲是fa,统计各节点 子节点数目dp[u]=1;for(int i = 0; i < G[u].size(); ++i) {  int v = G[u][i];cout<<"v="<<v<<"  ";if(v != fa) {cout<<"dfs"<<v<<","<<u<<"  ";dfs(v, u);  //递归转化以v为根的子树dp[u]+=dp[v];}}
}void dp_dfs(int son,int fa){int maxx=0;for(int i = 0; i < G[son].size(); ++i) {int v = G[son][i];if(v != fa) {//cout<<"dfs"<<v<<","<<son<<"  ";dp_dfs(v, son); maxx=max(maxx,dp[v]);//cout<<"maxx="<<maxx<<"  ";}}//更新答案  maxx = max(n-dp[son], maxx);//n-dp[son]==“上方子树”  maxx理解为“自己的子树”//cout<<"n-dp"<<son<<"="<<n-dp[son]<<"  ";//cout<<"newmaxx="<<maxx<<"  ";if(maxx < ans)  {  tot = 1;  ans = maxx;  num[tot] = son;  }  else if(maxx == ans)  {  tot++;  num[tot] = son;  }  }
int main()
{  int u,v;  while(scanf("%d",&n)==1)  {  init();for(int i=1;i<n;i++) G[i].clear();for(int i=1; i<n; i++){scanf("%d%d",&u,&v);G[u].push_back(v);G[v].push_back(u);}dfs(1, 0);  for(int i=1;i<=n;i++){cout<<"dp"<<i<<"="<<dp[i]<<" ** ";};//cout<<endl;dp_dfs(1, 0);  sort(num+1, num+tot+1);  printf ("%d",num[1]);  for(int i=2; i<=tot; i++)  printf (" %d",num[i]);  printf ("\n");  }  return 0;
}  

代码调试:

更好的代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <iostream>using namespace std;int N; // 1<= N <= 20000
const int maxn = 20000;
vector<int> tree[maxn + 5]; // tree[i]表示节点i的相邻节点
int d[maxn + 5]; // d[i]表示以i为根的子树的节点个数#define INF 10000000int minNode;
int minBalance;void dfs(int node, int parent) // node and its parent
{d[node] = 1; // the node itselfint maxSubTree = 0; // subtree that has the most number of nodesfor (int i = 0; i < tree[node].size(); i++) {int son = tree[node][i];if (son != parent) {dfs(son, node);d[node] += d[son];maxSubTree = max(maxSubTree, d[son]);}}maxSubTree = max(maxSubTree, N - d[node]); // "upside substree with (N - d[node]) nodes"if (maxSubTree < minBalance){minBalance = maxSubTree;minNode = node;}
}int main()
{int t;scanf("%d", &t);while (t--){scanf("%d", &N);for (int i = 1; i <= N - 1; i++){tree[i].clear();}for (int i = 1; i <= N-1; i++){int u, v;scanf("%d%d", &u, &v);tree[u].push_back(v);tree[v].push_back(u);}minNode = 0;minBalance = INF;dfs(1, 0); // fist node as rootprintf("%d %d\n", minNode, minBalance);}return 0;
}

参考资料:百度百科https://baike.baidu.com/item/树的重心/20416316

树形dp——树的重心(2) 代码调试理解相关推荐

  1. POJ - 4045 Power Station(树形dp/树的重心)

    题目链接:点击查看 题目大意:给出一个n个节点的树,我们需要选出一个节点,到其余任何节点的距离和最小 题目分析:这个题我的第一反应是用树的重心,先求出来符合条件的点,然后再跑一遍dfs求距离,最后输出 ...

  2. 树形dp树的重心(D - Godfather POJ - 3107)

    题目链接:https://cn.vjudge.net/contest/277955#problem/D 题目大意:求树的重心(树的重心指的是树上的某一个点,删掉之后形成的多棵树中节点数最大值最小). ...

  3. 树形dp ——树的重心

    1.只需要求出最大子树中节点数最小的数目即可 题意:有一个国王要把他的领土分给两个儿子,国王的领土是一棵树,N个结点,N-1条边把这些结点连起来,现在大小儿子要选择一个点作为他的首都,那么除首都分别是 ...

  4. 树形DP+树状数组 HDU 5877 Weak Pair

    1 //树形DP+树状数组 HDU 5877 Weak Pair 2 // 思路:用树状数组每次加k/a[i],每个节点ans+=Sum(a[i]) 表示每次加大于等于a[i]的值 3 // 这道题要 ...

  5. [BZOJ3197][Sdoi2013]assassin(树形DP+树同构+二分图最优匹配)

    关于树同构,有一个神奇的性质: 一棵树的重心只有 111 个或 2" role="presentation" style="position: relative ...

  6. HDU - 5242 Game(树形dp+树链剖分/树上贪心+思维)

    题目链接:点击查看 题目大意:给出一棵包含n个节点的树,每个节点都有一个权值,整棵树的根是点1,问从点1开始向下一直走到叶子节点,可以走k次,怎么样走权值和最大,每个节点被走过一次后权值会变为0 题目 ...

  7. 树形dp——树的最远距离 hdu2196

    [题意]求树上每个点的最远距离是多少 对于<u,v>(有向), dp[u][0]表示在u的子树下u的最远距离是多少 dp[u][1]表示在u的子树下(和dp[u][0]不是同一孩子)u的次 ...

  8. 洛谷4895 BZOJ3162 独钓寒江雪 树形dp 树哈希

    题目链接 题意: 给定一棵无根树,求其中本质不同的独立集的个数.独立集就是一个集合中的点之间都没有边直接相连.n<=5e5n<=5e5n<=5e5,对1e9+71e9+71e9+7取 ...

  9. BZOJ 1827: [Usaco2010 Mar]gather 奶牛大集会 树形DP + 带权重心

    Description Bessie正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会.当然,她会选择最方便的地点来举办这次集会.每个奶牛居住在 N(1<=N<=100,0 ...

最新文章

  1. cdt仿真程序,可模拟RTU使用CDT92协议和主站端通讯
  2. 各大公司广泛使用的在线学习算法FTRL详解
  3. 集合还有这么优雅的运算法?
  4. python安装依赖失败_python执行安装第三方依赖numpy失败:error: Unable to find vcvarsall.bat...
  5. 11.22Daily Scrum(2)
  6. java itextpdf使用HTML模板生成pdf文件,并设置table
  7. Qt编写自定义控件29-颜色选取面板
  8. Android.mk调用bin/shell
  9. sps的process插件安装包_SPSS的Process插件下载和安装
  10. Windows编程之钩子程序
  11. 《凤凰项目》读书笔记
  12. 200plc与施耐德ATV610变频器modbus通讯
  13. 招商银行吴颖:招行大数据应用经验分享
  14. 英语——非谓语动词——不定式【学习笔记】
  15. Linux基线检查( 一)
  16. Kaldi入门教程 aishell脚本
  17. 如何使用CC协议声明
  18. 矩阵乘以一个系数和行列式乘以一个系数
  19. threeJS 创建地月系
  20. 文章html格式排版工具,网站文章排版美化:推荐几款实用丰富的在线编辑器 | 闲一鱼博客...

热门文章

  1. tornado 入门
  2. 智能手机收邮件之NOKIA
  3. Linux运维之道之ENGINEER1.1(配置邮件服务器,数据库管理基础,表数据管理)
  4. 全面认识网络诊断命令功能与参数——netsh diagnostic命令
  5. 《Linux企业应用案例精解》一书已由清华大学出版社出版
  6. 微软:Windows 7 SP1将于本月正式发布
  7. Java类和对象的初始化顺序
  8. 检测用户是允许还是拒绝使用摄像头.
  9. 定制SPS实战记录 系列之一
  10. centos在文本中搜索字符串_CentOS查找所有文件中某个字符串