Description
小Q来到了一个随机的国度。这个国度由n座城市和m条双向道路构成。因为这个国度崇尚随机,因此m条边是用随机
选择两端点的方式生成的。充满好奇的小Q想在这里进行k次随机的旅行,每次的起点和终点也是随机选择的。在每
次出发之前,他会使用导航系统计算两点间最少需要经过几条道路。请写一个程序,帮助小Q计算两点间的最短路
Input
第一行包含3个正整数n,m,k(2<=n<=100000,1<=m<=300000,1<=k<=10000),分别表示点数、边数和询问数。
接下来m行,每行两个正整数u_i,v_i(1<=u_i,v_i<=n),表示一条双向道路。输入数据保证不会有重边和自环。
接下来k行,每行两个正整数u_i,v_i(1<=u_i,v_i<=n,u_i!-v_i),表示一次询问。
输入数据保证随机生成,且除了样例之外均满足n=100000,m=300000。
本题共3组数据。
Output
输出k行,每行一个整数,即最少经过的边数,若无解输出-1。
Sample Input
6 5 5
1 2
2 3
1 3
1 4
4 5
1 3
4 2
3 5
5 1
4 6
Sample Output
1
2
3
2
-1
分析:
因为图是随机的,所以这两个点的距离不会太长(大概在
l
o
g
2
n
≈
18
log_2n≈18
log2n≈18)。对于两个点,我们用并查集判断是否连
通。然后双向bfs搜索,因为两边搜的距离为
l
o
g
2
n
2
≈
9
\frac{log_2n}{2}≈9
2log2n≈9,也就是大概会搜到
2
∗
2
9
2*2^9
2∗29的点。因为题目询问随机,这样就可以通过了。
代码:
/**************************************************************
Problem: 5049
User: ypxrain
Language: C++
Result: Accepted
Time:4272 ms
Memory:7932 kb
****************************************************************/
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
const int maxn=1e5+7;
const int maxe=3e5+7;
using namespace std;
int n,m,k,x,y,ans,cnt;
int ls[maxn],dis[maxn],vis[maxn],op[maxn],p[maxn];
struct edge{
int y,next;
}g[maxe*2];
queue <int> q;
void add(int x,int y)
{
g[++cnt]=(edge){y,ls[x]};
ls[x]=cnt;
}
int find(int x)
{
if (!p[x]) return x;
return p[x]=find(p[x]);
}
void uni(int x,int y)
{
int u=find(x),v=find(y);
if (u==v) return;
p[u]=v;
}
void bfs(int s)
{
while (!q.empty()) q.pop();
q.push(x);
q.push(y);
vis[x]=s,vis[y]=s;
dis[x]=0,dis[y]=0;
op[x]=0,op[y]=1;
while (!q.empty())
{
int x=q.front();
q.pop();
for (int i=ls[x];i>0;i=g[i].next)
{
int y=g[i].y;
if (vis[y]==s)
{
if (op[y]!=op[x])
{
ans=dis[x]+dis[y]+1;
return;
}
continue;
}
dis[y]=dis[x]+1;
op[y]=op[x];
vis[y]=s;
q.push(y);
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
uni(x,y);
}
for (int i=1;i<=k;i++)
{
scanf("%d%d",&x,&y);
if (find(x)!=find(y)) printf("-1\n");
else
{
bfs(i);
printf("%d\n",ans);
}
}
}