【题解】2020-2021 SWERC I.Emails

link

题意

给定\(n\)个人之间的关系图(无向图),一开始每个人的通讯录中有与他相邻的人的练习方式。在每一轮中,每个人都会将自己通讯录中所有人的联系方式发送给他当前通讯录中的所有人(注意不是一开始与他相邻的人)。求多少轮后所有都有所有其他人的联系方式。如果正确答案为\(E\),则你输出\(E\)或\(E+1\)都视为正确。

\(2\le n\le 10^5,1\le m\le 10^5\)

题解

易得在有限轮之后该过程一定停止,且两个人\(u,v\)在\(\lceil \log_2(d(u,v))\rceil\)轮后相互知晓对方,故\(E=\lceil \log_2(Diam (G))\rceil\)。由于最后允许和答案有一轮的容忍程度,我们可以不需要精确求出图直径的长度。我们从任意一点出发\(BFS\),设与其最远的点和它的距离为\(D\),由于

\[D\le Diam(G)\le 2D, \]

\[\log_2 D\le \log_2 Diam(G)\le 1+\log_2 D, \]

所以

\[\log_2 Diam(G)\le \log_2 D+1\le \log_2 Diam(G)+1, \]

即\(E\le \log_2 D+1\le E+1\),于是我们输出\(\lceil \log_2 D\rceil+1\)即可。

\(Diam(G)\le 2D\)的证明

反证法,假若不然,则有\(Diam(G)>2D\)。不妨设\(s,t\)是直径\(Diam(G)\)的两端点,即\(d(s,t)=Diam(G)\),由于\(d(u,s)\le D,d(t,u)\le D\),所以\(s\rightarrow u\rightarrow t\)这条路径的长度不大于\(2D\),这与\(d(s,t)=Diam(G)>2D\)矛盾,故\(Diam(G)\le 2D\)。

#include <bits/stdc++.h>
#define cle(x) memset(x,0,sizeof(x))
using namespace std;
const int N=100005,M=200005;
typedef long long ll;
const ll INF=1ll<<55;
struct edge{int v,w,nt;}e[M];
int cnt=0,h[N];
void add(int u,int v,int w){
	e[++cnt].v=v;e[cnt].nt=h[u];e[cnt].w=w;h[u]=cnt;
}
int n,m,k,tag[N],S[N],p=0,a[N],b[N],cs=0,p1=0,p2=0,c[N],P,p3;
ll ans,d[N];
struct node{
	int u;ll x;
	bool operator<(const node &b)const{
		return x>b.x;
	}
};
priority_queue<node> q;
int dij(int s){
	while(!q.empty())q.pop();
	for(int i=1;i<=n;i++)d[i]=INF;
	d[s]=0;q.push(node{s,0});
	while(!q.empty()){
			node na=q.top();q.pop();
			if(na.x!=d[na.u])continue;
			for(int i=h[na.u];i;i=e[i].nt){
				int v=e[i].v;
				if(d[na.u]+e[i].w<d[v]){
					d[v]=d[na.u]+e[i].w;
					q.push((node){v,d[v]});
				}
			}
		}
		int res=0;
	for(int i=1;i<=n;i++){
		if(d[i]==INF){printf("-1");exit(0);}
		res=max<int>(res,d[i]);
	}
	return res;
}
void f1(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int x,y,z;scanf("%d%d",&x,&y);
		add(x,y,1);add(y,x,1);
	}
	int res=dij(1);
	int ans=(int)ceil(log2(res))+1;
	printf("%d",ans);
}
int main(){
	f1();
	return 0;
}
上一篇:Unity教程2D入门:28 二段跳 & 单向平台


下一篇:理解CSS transform 2d变换