示例1:
输入:
4 2
1 2
3 1
3 4
2 4
输出:2
说明:
They can meet at place 1 or 3.
题意:从K个点到达不联通图某个点需要的最短时间,这个最短时间是这K个人最后到达的人所需的时间。
思路:(我觉得官方给的题解挺好理解的就直接复制过来了)
一句话题解:考虑距离最远的两个关键点,设它们的距离为d,d/2上取整即为答案。
必要性:这两个人要碰面,必然要走至少d/2步。
充分性:我们取两人路径中和一头距离为d/2上取整的一个点,让所有人在这相聚。如 果有一个人在d/2时间内到不了,那么它和路径两头中与它远的那一头的距离大于d,与 最远的假设矛盾。
找到这样最远的一对点类似找树的直径。可以直接dp,也可以采用两遍dfs:
从任意一个关 键点开始,找到离它最远的关键点x,再从x开始dfs,找到的新的最远点和x形成的就是直径。
当然对着题面直接dp也是可以做的,但是比较难写。(不会写dp,还需提升能力)。
1、dfs代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int inf=0x3f3f3f3f,maxn=1e5+5; 4 vector<int>a[maxn]; 5 int top,n,k,x,y,t,summ,book[maxn]; 6 void dfs(int p,int q,int step)//p为当前节点,q记录父节点,step记录已走步数 7 { 8 if(book[p]&&step>summ)//当当前步数大于已标记最大步数和该点上有人时更新最大步数和标记最远端点,以便做第二次寻找最长路的起点 9 summ=step,top=p; 10 for(int i=0; i<a[p].size(); i++) 11 { 12 if(a[p][i]!=q) 13 dfs(a[p][i],p,step+1); 14 } 15 } 16 int main() 17 { 18 scanf("%d%d",&n,&k); 19 for(int i=1; i<n; i++) 20 { 21 scanf("%d%d",&x,&y); 22 a[x].push_back(y),a[y].push_back(x); 23 } 24 for(int i=0; i<k; i++) 25 { 26 scanf("%d",&t); 27 book[t]=1;//book数组标记某个点有人 28 } 29 dfs(t,0,1); 30 dfs(top,0,1); 31 printf("%d\n",summ/2); 32 return 0; 33 }
2、dp代码(以后更新)