3.Formula 1(f1.cpp/c/pas)
【问题描述】
F1,中文全称为一级方程式锦标赛,是最高级的方程式赛车比赛,现在你作为一名选手参加了一场 F1 的比赛,比较特殊地,本次比赛是在一个 N 个点 M 条边的无向图上举行的。
起点是 S,终点是 T,每条边长度为 1 公里,赛车每行驶 1 公里耗油 1 个单位,途中共有 k 个加油站,每经过加油站时,可以把油加满,但你的赛车设计顾问告诉你,油箱容量越大,赛车跑的就越慢。为了追求最快的速度,在能顺利到达终点,不会中途没油的前提下,
你希望最小化油箱的容量(注意,虽然油箱变小可能导致路径变长,但我们只关心最小化的油箱)。
【输入】
输入文件 f1.in。
第一行一个正整数 T 表示测试数据组数,每组数据格式如下:
第一行三个整数,N,M,K,表示无向图的点数,边数,加油站数。
第二行 K 个正整数 i1,i2..ik 表示这些点上有加油站(可能重复,保证至少一个加油站在S 点)。
接下来 M 行,每行两个正整数 Bi,Ei 表示有一条连接(Bi,Ei)的双向边(可能有重边和自环)。
最后一行两个正整数 S,T 表示起点、终点。
【输出】
输出文件名为 f1.out。
对于每组数据,如果没法到达终点,输出-1,否则输出最小化的油箱容量。
【输入样例 】
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--;
}
}