2019牛客多校训练营(第四场)——A

原题题址

题目描述
A new city has just been built. There’re n interesting places numbered by positive numbers from 1 to n. In order to save resources, only exactly n−1 roads are built to connect these nn interesting places. Each road connects two places and it takes 1 second to travel between the endpoints of any road.
There is one person in each of the places numbered x 1 , x 2 … x k x_1,x_2 \ldots x_k x1,x2xk
and they’ve decided to meet at one place to have a meal. They wonder what’s the minimal time needed for them to meet in such a place. (The time required is the maximum time for each person to get to that place.)

输入描述:

First line two positive integers, n,k - the number of places and
persons. For each the following n-1 lines, there’re two integers
a,ba,b that stand for a road connecting place aa and bb. It’s
guaranteed that these roads connected all n places.On the following
line there’re k different positive integers x 1 , x 2 … x k x_1,x_2 \ldots x_k x1,x2xk
separated by spaces. These are the numbers of places the persons are
at.

输出描述:

A non-negative integer - the minimal time for persons to meet together.

示例1

输入

4 2
1 2
3 1
3 4
2 4

输出

2

说明

They can meet at place 1 or 3

.
备注:

1 ≤ n ≤ 1 0 5 , 1 ≤ n ≤ 1 0 5 1 \leq n \leq 10^5,1≤n≤10^5 1n105,1n105

题目到手,翻译为先:

一座新城市刚刚建成。有n个有趣的地方用从1到n的正数编号。为了节省资源,只有n-1条道路可以连接这n个有趣的地方。每条道路连接两个地方,在任何道路的端点之间行驶需要1秒钟。在每个编号为 x 1 , x 2 … x k x_1,x_2 \ldots x_k x1,x2xk的地方都有一个人 。 他们决定在一个地方见面吃饭。他们想知道在这样一个地方见面所需的最短时间是什么。(所需时间是每个人到达该地点的最长时间。)

大意可以理解为生活中的一个场景:
在n个地方分散着k个网友,每个网友分别在不同的k个地方,他们要搞线下见面会。请问他们选在哪里,可以使网友到齐的时间最短。

那么作为一个“马后炮”,我想说,这个就是把网友们的点组合成树,再求树的直径。

树的直径:
定义:

给定一棵树,树中每条边都有一个权值,树中两点之间的距离定义为连接两点的路径边权之和。树中最远的两个节点之间的距离被称为树的直径,连接这两点的路径被称为树的最长链。后者通常也可称为直径,即直径是一个数值概念,也可代指一条路径。

求解思路:

先从任意一点P出发,找离它最远的点Q,再从点Q出发,找离它最远的点R,R到Q的距离就是是的直径。
1)当P点在直径上时,显然Q时靠P较远的一条直径的端点,而R是另一个端点,RQ就是直径。
2)当P不在直径上时:
反证法:假设PQ不是直径。
(1)当PQ与直径AB有及交点时(如下图),A-P的距离:AC+PC 小于 P-Q的距离:PC+CQ(Q离P最远),所以CQ>AC。所以QC+CB > AC+CB = AB。
这与AB为直径的题设矛盾,故不成立

图1(2)PQ与直径不相交:
证明方法和上面的方法相同;还是不知道的将MN看做一个节点(MN长度对PQ,AB的长度不能产生影响),就转化为上一种情况了,结论和上一种情况一样。
图2

具体求法:

dfs,bfs,树形dp。但是我就最简单的dfs稍稍有些了解。
DFS:

#include"iostream"
#include"cstdio"
using namespace std;
const int maxn = 1e5;
struct Edge{
	int Next,to,Value;
}e[maxn*2+5];
int N,M,cnt = 0,des,ans = 0,head[maxn+5]//des是离1点最远的点。
void add_E(int a,int b,int c){
	e[++cnt].to = b;
	e[cnt].Next = head[a];
	head[a] = cnt;
	e[cnt].Value = c;
}
void dfs(int x,int fa,int dis){
	if(dis>ans){
		ans = dis,des = x;
	}
	for(int i = head[x];i;i = e[i].Next){
		int pp = e[i].to;
		if(pp == fa)continue;
		dis += e[i].Value;
		dfs(pp,x,dis);
	}
	
	
}
int main(){
	scanf("%d%d",&N,&M);
	for(int i = 1;i <= M;i++){
		scanf("%d%d%d",&x,&y,&v);
		add_E(x,y,v);
		add_E(y,x,v);
	}
	dfs(1,0,0);
	dfs(des,0,0);
	cout << ans<<endl;
	return 0;
}

本题AC代码:

    #include"iostream"
    #include"cstdio"
    #include"cstring"
    using namespace std;
    const int maxn = 1e5;
    struct Edge{
    	int Next,to;
    }e[maxn*2+5];
    int N,M,cnt = 0,des,ans = 0,head[maxn+5],in[maxn+5];
    void add_E(int a,int b){
    	e[++cnt].to = b;//该条边与a连接的点
    	e[cnt].Next = head[a];//记录一条与a点连接的边的下标
    	head[a] = cnt;//保存边的下标,以便查询
    }
    void dfs(int x,int fa,int dis){
    	if(dis>ans&&in[x]){//限定树的节点
    		ans = dis,des = x;
    	}
    	for(int i = head[x];i;i = e[i].Next){
    		int pp = e[i].to;
    		if(pp == fa)continue;//防止成环
    		dfs(pp,x,dis+1);
    	}
    	
    	
    }
    int main(){
    	scanf("%d%d",&N,&M); 
    	memset(head,0,sizeof(head));
    	memset(in,0,sizeof(in));
    	for(int i = 1;i <= N - 1;i++){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		add_E(x,y);
    		add_E(y,x);
    	}
    	for(int i = 1;i <= M;i++)
    	{
    		int a;
    		scanf("%d",&a);
    		in[a] = 1;
    	}
    	dfs(1,0,0);
    	dfs(des,0,0);
    	cout << (ans+1)/2<<endl;
    	return 0;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值