树的重心-acwing的学习

数和图的存储方式:

树是一种特殊的图 ,是无环连通图。

有向图的存储:
  1. 邻接矩阵 g[a,b] a和b的关系 权重 bool值
  2. 邻接表 有n个点 就开了n个单链表 每一个节点上开了一个单链表
每个单链表上存储的值是什么?
  • 存储这个点可以走到哪个点。
  • 单链表里面的顺序是无关紧要的,只要能表示此点可以到哪个点就可以。 二维数组,记录 ab ba,如果是无权重, 就是bool或者01表示。如果有权值就记录权值。
树图的遍历有两种方式:
  1. 深度优先遍历 一般的题目都是只遍历一次
  2. 宽度优先遍历 一般的题目都是只遍历一次

无向图也是一种特殊的有向图
考虑有向图如何遍历
树也是一种特殊的图

题目:

树的重心:

给定一颗树,树中包含 n 个结点(编号 1∼n)和 n−1 条无向边。

请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。

重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。

输入格式: 第一行包含整数 n,表示树的结点数。 接下来 n−1 行,每行包含两个整数 a 和 b,表示点 a 和点 b 之间存在一条边。

输出格式: 输出一个整数 m,表示将重心删除后,剩余各个连通块中点数的最大值。

代码如下:

#include<iostream>
#include<cstring>
using namespace std;
const int N=1e6+10;
int h[N],e[N],ne[N];
int idx;//记录每次的操作数
int n;//记录总的输入数
int ans=N;//记录答案
bool st[N];//记录 走过的点
void add(int a,int b)//单链表中的头插法 基操
{
	e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
int bfs(int u)返回以此点为根节点的树的大小
{
	st[u]=true;
	int sum=1; int res=0;
	//sum指以此点为根节点的树的大小  res指删除此点后剩余连通块中 树的最大值
	for(int i=h[u];i!=-1;i=ne[i])
	{
		int j=e[i];//只遍历图每个点一次
		if(!st[j])
		{
			int s=bfs(j);
			res=max(res,s);//比较此点以下的连通块的大小
			sum+=s;//sum指的是一次点为根节点的树的大小因此要加上子树的大小
		}
	}
	res=max(res,n-sum);//和此点上面的连通块比较
	ans=min(ans,res);//全局的 比较 从而找出树的重心
	return sum;
}
int main()
{
	memset(h,-1,sizeof h);
	cin>>n;
	int a,b;
	for(int i=1;i<n;i++)
	{
		cin>>a>>b;
		add(a,b); add(b,a);
	}
	bfs(1);
	cout<<ans<<endl;
	return 0;
}

此算法的学习来自网站 acwing
y总的方法是在秒的一批
推荐学习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

镜子的分享

感谢老铁支持!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值