洛谷 P1395 会议(树的bfs dfs)

输入样例:

4
1 2 
2 3 
3 4 

输出样例: 

2 4

思路: 

将题中的图看作以1为根节点的一棵树
d[i]表示所有点到i的距离之和
size[i]表示以i为根节点的子树的点的个数 
假设x是y的父节点
d[y] = d[x] + (n-size[y]) + size[y]
这是一个从上到下的过程
所以我们首先可以利用宽搜求所有点到1的距离之和d[1]
然后再用一个深搜求所有点以i为根节点的子树点的个数size[i](这是一个自下而上的过程,所以要跟求d[i]的深搜分开)
再用一个深搜求所有点到点i的距离之和d[i]
结果就是最小的d[i]对应的最小的i

代码:

#include <iostream>
#include <cstring>
using namespace std;
const int N=1e5+5;
int n;
int d[N],dist[N]; //dist记录所有点到1的距离 
int e[N],ne[N],h[N],idx;
int q[N],size[N];
bool st[N];
void add(int a,int b){
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void bfs(){
	memset(dist,-1,sizeof dist);
	int hh=0,tt=-1;
	q[++tt]=1;
	dist[1]=0;
	while (hh<=tt){
		int t=q[hh++];
		for (int i=h[t];i!=-1;i=ne[i]){
			int j=e[i];
			if (dist[j]==-1){
				dist[j]=dist[t]+1;
				q[++tt]=j;
			}
		}
	}
	for (int i=1;i<=n;i++) d[1]+=dist[i];
}
void dfs1(int x){
	st[x]=true;
	size[x]=1;
	for (int i=h[x];i!=-1;i=ne[i]){
		int j=e[i];
		if (!st[j]){
			dfs1(j);
			size[x]+=size[j];
		}
	}
}
void dfs2(int x){
	st[x]=true;
	for (int i=h[x];i!=-1;i=ne[i]){
		int j=e[i];
		if (!st[j]){
			d[j]=d[x]+n-2*size[j];
			dfs2(j);
		}
	}
}
int main(){
	cin>>n;
	memset(h,-1,sizeof h);
	for (int i=0;i<n-1;i++){
		int a,b; cin>>a>>b;
		add(a,b),add(b,a);
	}
	bfs(); //宽搜求所有点到1的距离 
	dfs1(1);
	memset(st,false,sizeof st);
	dfs2(1);
	int res=1,len=d[1];
	
	for (int i=1;i<=n;i++){
		if (d[i]<len) len=d[i],res=i;
	}
	//for (int i=1;i<=n;i++) cout<<dist[i]<<' ';
	//cout<<endl;
	//for (int i=1;i<=n;i++) cout<<size[i]<<' ';
	//cout<<endl;
	//for (int i=1;i<=n;i++) cout<<d[i]<<' ';
	//cout<<endl;
	cout<<res<<' '<<len<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值