2019牛客暑期多校训练营(第四场)A
2019-08-01 00:35
555 查看
题意:给定n个顶点,n-1条边权为1的边,将各个顶点连成一个最小生成树,再给定一个K,表示有多少个人,每个人都在特点的一个顶点上,现在这些人要相会,求使得这些人能够相聚在一起的最短时间。
看了标程,答案就是K个人当中那2个距离最远的人的距离d,答案就是d/2向上取整。
证明:
必要性:K个人当中,最远的那2个人u,v要相遇,则其中一个必定至少要走⌈d/2⌉的步数。
充分性:我们取最远那2个人u,v相会的那个点,这个点一定是该路径上的中点或中点附近,设该点为point。假若有另外一个人k,k到point的距离大于⌈d/2⌉,那么u,v这两个人的距离就不是所有人中最远的了,这样就与假设矛盾。
综上,命题成立。
那么这么一转化,其实本题求的就是一颗树的直径。
什么是树的直径?树的直径就是:树中距离最远的两个节点的距离。怎么求树的直径呢? 方法就是:先在树中任意找一节点设为根v1,对其求BFS,求出v1到其它所有节点的距离,取其中最远距离的节点为v2,再设v2为根,对其求BFS,求出v2到其它所有节点的距离,取其中最远距离的节点v3,那么v2与v3的距离就是树的直径了——两遍BFS遍历整棵树就可以求出其直径。
关于树的直径,还可参考以下博客:
https://www.cnblogs.com/Khada-Jhin/p/10195287.html (树的直径性质及算法证明)
https://www.geek-share.com/detail/2554651640.html
代码如下:
#include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<queue> using namespace std; typedef long long ll; const int maxn=1e5+5; const int inf=0x7f7f7f7f; int head[maxn],cnt; int n,K,k[maxn]; int dis[maxn]; bool vis[maxn]; struct Road { int u,v,w,next; Road(int u=0,int v=0,int w=0) { this->u=u; this->v=v; this->w=w; }; }r[2*maxn]; void addedge(int u,int v,int w) { r[cnt].u=u; r[cnt].v=v; r[cnt].w=w; r[cnt].next=head[u]; head[u]=cnt++; r[cnt].u=v; r[cnt].v=u; r[cnt].w=w; r[cnt].next=head[v]; head[v]=cnt++; } void BFS(int s) { queue<int> Q; memset(vis,0,sizeof(vis)); memset(dis,0,sizeof(dis)); //WA了两次,因为把后面的sizeof(dis)写成sizeof(vis)...(捂脸) Q.push(s); vis[s]=1; while(!Q.empty()) { int u=Q.front(); Q.pop(); for(int i=head[u]; i ;i=r[i].next) { if(!vis[r[i].v]) { dis[r[i].v]=dis[u]+1; //1为边权,如果边权不为1,就修改为r[i].w就可以了 Q.push(r[i].v); vis[r[i].v]=1; } } } } int main() { scanf("%d%d",&n,&K); memset(head,0,sizeof(head)); cnt=2; for(int i=1;i<n;++i) { int u,v; scanf("%d%d",&u,&v); addedge(u,v,1); } for(int i=1;i<=K;i++) scanf("%d",&k[i]); BFS(k[1]); //第一次BFS的起点是任选的,啥都行 int v1=0,temp=0; for(int i=1;i<=K;i++) { if(temp<dis[k[i]]) //找到K个人当中,距离最远的那个v1 temp=dis[v1=k[i]]; } BFS(v1); //对v1进行BFS int v2=0; temp=0; for(int i=1;i<=K;i++) { if(temp<dis[k[i]]) //找到与v1距离最远的节点v2 temp=dis[v2=k[i]]; } printf("%d\n",(dis[v2]+1)/2); //v1到v2的距离向上取整即可 return 0; }
相关文章推荐
- 2019牛客暑期多校训练营 第四场
- 2019牛客暑期多校训练营(第二场) - F - Partition problem - 枚举
- 2019牛客暑期多校训练营 第三场
- 2019牛客暑期多校训练营(第七场)
- 2019牛客暑期多校训练营(第一场)J:Fraction Comparision
- 2019牛客暑期多校训练营(第七场)A(暴力)
- 2019牛客暑期多校训练营 第五场
- 2019牛客暑期多校训练营(第七场)H(数位DP)
- 2019牛客暑期多校训练营(第一场) - A - Equivalent Prefixes - 单调栈
- 2019牛客暑期多校训练营(第一场) A Equivalent Prefixes ( st 表 + 二分+分治)
- 暑假N天乐【比赛篇】 —— 2019牛客暑期多校训练营(第一场)
- 暑假N天乐【比赛篇】 —— 2019牛客暑期多校训练营(第二场)
- 2019牛客暑期多校训练营(第一场)
- 2019牛客暑期多校训练营(第三场)
- 2019牛客暑期多校训练营(第五场)G(DP)
- 2019牛客暑期多校训练营(第一场) - E - ABBA - 贪心 - dp - 组合
- 2019牛客暑期多校训练营(第六场)
- 2019牛客暑期多校训练营(第二场)
- 2019牛客暑期多校训练营(第三场)
- 2019牛客暑期多校训练营(第二场) - H - Second Large Rectangle - dp