【输入样例 】
2
6 6 3
1 3 6
1 2
2 3
4 2
5 6
4 5
3 4
1 6
7 10 3
1 3 4
1 2
4 2
7 5
4 5
7 1
2 5
7 2
3 7
3 2
5 1
4 6
【输出样例 】
3
-1
【数据范围】
对于 30%的数据,N<=200,M<=2000。
对于 60%的数据,N<=1000,M<=10000。
对于 100%的数据,1<=K,S,T<=N<=100000,1<=M<=150000,1<=T<=5。
————————————————————————————————————————
【题解】【BFS+并查集】
【这道题的建图方法十分的精妙啊:每条边中间加一个点,拆成两条边。】
【把所有的加油站加入队列,并把起点和终点也加入队列,然后跑BFS,每次将一条边的左右两个端点并到一个集合中,直至起点和终点在一个集合中时,输出】
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[600010],nxt[600010],p[500010],tot;
int val[500010],dis[500010],fa[500010];
int T,n,m,k,s,e;
bool b[500010];
int find(int x)
{
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
inline void add(int x,int y)
{
tot++; a[tot]=y; nxt[tot]=p[x]; p[x]=tot;
tot++; a[tot]=x; nxt[tot]=p[y]; p[y]=tot;
}
inline void clear()
{
memset(b,0,sizeof(b));
memset(p,-1,sizeof(p));
memset(dis,0,sizeof(dis));
memset(nxt,-1,sizeof(nxt));
tot=0;
}
int main()
{
freopen("f1.in","r",stdin);
freopen("f1.out","w",stdout);
int i,j;
scanf("%d",&T);
while(T)
{
clear();
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=k;++i) scanf("%d",&val[i]),b[val[i]]=1;
int tt=n;
for(i=1;i<=m;++i)
{
int x,y;
scanf("%d%d",&x,&y);
tt++; add(x,tt); add(tt,y);
}
scanf("%d%d",&s,&e);
for(i=1;i<=tt;++i) fa[i]=i;
queue<int>que;
if(!b[s]) b[s]=1,que.push(s);
if(!b[e]) b[e]=1,que.push(e);
for(i=1;i<=k;++i)
if(b[val[i]]) que.push(val[i]);
bool r=0;
while(!que.empty())
{
if(r) break;
int u=que.front(); que.pop();
int v=p[u];
while(v!=-1)
{
int f1=find(u),f2=find(a[v]);
if(f1!=f2) fa[f1]=f2;
if(find(s)==find(e)) {printf("%d\n",dis[u]+1); r=1; break; }
if(!b[a[v]])
{
dis[a[v]]=dis[u]+1;
b[a[v]]=1;
que.push(a[v]);
}
v=nxt[v];
}
}
if(!r) printf("-1\n");
T--;
}
}