向前走莫回头❤

【NOIP 模拟题】[山东多校联合模拟赛 day1 T3] Formula 1 (BFS+并查集)

 

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--;
	 }
}



 

posted @ 2016-08-23 19:51  lris0-0  阅读(107)  评论(0编辑  收藏  举报
过去的终会化为美满的财富~o( =∩ω∩= )m