ZOJ - 3820 Building Fire Stations

本文介绍了一种解决树形结构中寻找两个点使所有点到这两点路径长度最小值最小的问题的方法。通过找到树的直径并将其分为两部分,进而确定关键点的位置来求解。文章详细展示了算法实现过程及代码细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给你一棵树求两个点使得树上所有点到这两个点路径长度的最小值最小


取直径的中点拆掉拆成两棵树,分别求两边的直径中点就是答案==QAQ细节真多==还会爆栈不开心


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep(j,k,l) for (int j=k;j<=l;j++)
#define N 400005

using namespace std;
int T,n,cnt,lft,rgt,to[N*2],ne[N*2],st[N],deep[N],miaom[3];
int used[N],last[N],que[N];

void add(int k,int l){
	
	to[++cnt]=l;
	ne[cnt]=st[k];
	st[k]=cnt;
	
}

int bfs(int k){
	
	int head=0,tail=1,_=k;
	memset(used,0,sizeof(used));
	used[k]=1;que[1]=k;deep[k]=1;last[k]=0;
	while (head<tail){
		
		int x=que[++head];
		for (int i=st[x];i;i=ne[i])
			if (used[to[i]]==0&&(!((x==lft||x==rgt)&&(x+to[i]==lft+rgt)))){
				
				que[++tail]=to[i];
				deep[to[i]]=deep[x]+1;
				if (deep[to[i]]>deep[_]) _=to[i];
				used[to[i]]=1;
				last[to[i]]=x;
				
			}
		
	}
	return _;
	
}

void init(){
	
	cnt=0;
	scanf("%d",&n);
	rep(i,1,n) st[i]=0;
	rep(i,1,n-1){
		
		int k,l;
		scanf("%d%d",&k,&l);
		add(k,l);add(l,k);
		
	}
	
}

int mddl(int k,int poi){
	
	int o=bfs(k);
	int p=bfs(o);
	miaom[poi]=deep[p]/2;
	for (int i=p;i;i=last[i])
		if (deep[i]==deep[p]+1-(deep[p]+1)/2) return i;
	
}

void solve(){
	
	lft=0;rgt=0;
	rgt=mddl(1,0);lft=last[rgt];
	int k=mddl(lft,1),l=mddl(rgt,2);
	lft=0;rgt=0;
	n=bfs(1);
	printf("%d %d %d\n",max(miaom[2],max(miaom[1],abs(deep[k]-deep[l])/2)),k,l);
	
}

int main(){
	
	scanf("%d",&T);
	while (T--){
		
		init();
		solve();
		
	}
	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值