Comet OJ - Contest #12 C Bus Station(最短路)

题目链接

Bus Station

题意:

m m 个车站,有 n 1 + n 2 n1+n2 辆车单线车,其中 n 1 n1 辆车从第一个车站开往第 m m 个车站, n 2 n2 辆车从第 m m 个车站开往第一个车站。给一个二维矩阵表示每辆车到达每个站的时间。现在有两个人要在 s s 车站见面,一个人先到时间为 t 1 t1 ,一个人后到时间为 t 2 t2 ,先到的人不想在车站等待太长的时间,他可以随意地换乘其他车辆,并且在 t 2 t2 时间回到 s s 车站,要求求出其在车站等待地最短时间(包括换乘时在别的车站地等待时间)

思路:

观察到每一辆车地时间递增,不可能上一辆车两次,要求最短时间,考虑能不能使用最短路解决。首先对于一个线路地车站转化是不用等待时间地,那么就在他们之间连接权值为 0 0 的边,对于同一个车站的不同车之间的转换是需要时间的可以从按照时间小到大连边,权值即为差值。现在的问题就是如何添加起点和终点,我们将他们加入 s s 车站也当作一班只有一个站的车,就可以解决了,那么建完图就从起点向终点跑最短路即可。(注意每个点的编号),这样写完很可能会 w a wa ,因为当两辆车的到站时间一样的时候,如果把他们编成不同的点,那么对于先用哪一辆车就会出现问题,因为是单向,我的解决方法是将点按照时间离散化,保证时间相同对应点编号也相同,这样就可以解决了。

代码:

#include <bits/stdc++.h>
#define mk make_pair
#define pb push_back
#define ll long long
using namespace std;
const int N=2e6+10;
const int M=4e6+10;//开大点
struct edge{
	int to,next;ll w;
}e[M];
int head[N],cnt;
void add(int u,int v,ll w){
	e[cnt].to=v;e[cnt].next=head[u];e[cnt].w=w;head[u]=cnt++;
}
int TT;
int m,n1,n2,s,S,T,t1,t2;
vector<int>v[N],v1[N];//一个用作离散化
int getid(int x,int id){return lower_bound(v1[id].begin(),v1[id].end(),x)-v1[id].begin()+1;}
void built(){
	for(int i=1;i<=n1;i++){//相连车站的连边
		for(int j=1;j<m;j++)
		add(getid(v[j][i-1],j)+(j-1)*(n1+n2+2),getid(v[j+1][i-1],j+1)+j*(n1+n2+2),0);
		//cout<<getid(v[j][i-1],j)+(j-1)*(n1+n2+2)<<" "<<getid(v[j+1][i-1],j+1)+j*(n1+n2+2)<<endl;
	}
	for(int i=n1+1;i<=n2+n1;i++){
		for(int j=m;j>1;j--)
		add(getid(v[j][i-1],j)+(j-1)*(n2+n1+2),getid(v[j-1][i-1],j-1)+(j-2)*(n1+n2+2),0);
		//cout<<getid(v[j][i-1],j)+(j-1)*(n2+n1+2)<<" "<<getid(v[j-1][i-1],j-1)+(j-2)*(n1+n2+2)<<endl;
	}
	for(int i=1;i<=m;i++){//同一车站的连边
		sort(v[i].begin(),v[i].end());
		int mx=(i==s?n1+n2+2:n1+n2);
		for(int j=0;j<mx-1;j++){
			add(getid(v[i][j],i)+(i-1)*(n1+n2+2),getid(v[i][j+1],i)+(i-1)*(n1+n2+2),v[i][j+1]-v[i][j]);
			//cout<<getid(v[i][j],i)+(i-1)*(n1+n2+2)<<" "<<getid(v[i][j+1],i)+(i-1)*(n1+n2+2)<<" "<<v[i][j+1]-v[i][j]<<endl;
		}
	}
}
priority_queue<pair<ll,int> >q;
bool vis[N];
ll dis[N];
ll dij(){//最短路
	for(int i=0;i<=m*(n1+n2+2)+1;i++)vis[i]=0,dis[i]=1e18;
	while(!q.empty())q.pop();
	q.push(mk(0,S));dis[S]=0;
	while(!q.empty()){
		int now=q.top().second;q.pop();
		if(vis[now])continue;
		vis[now]=1;
		for(int i=head[now];~i;i=e[i].next){
			int v=e[i].to;
			//cout<<now<<" "<<v<<e[i].w<<endl;
			if(dis[v]>dis[now]+e[i].w){
				dis[v]=dis[now]+e[i].w;
				q.push(mk(-dis[v],v));
			}
		}
	}
	return dis[T];
}
int main()
{	
	scanf("%d",&TT);
	while(TT--){
		scanf("%d%d%d%d%d%d",&m,&n1,&n2,&s,&t1,&t2);
		for(int i=1;i<=m;i++)v[i].clear(),v1[i].clear();cnt=0;//注意初始化
		for(int i=0;i<=m*(n1+n2+2)+1;i++)head[i]=-1;
		for(int i=1;i<=m;i++){
			for(int j=1,x;j<=n1+n2;j++){
				scanf("%d",&x);v[i].pb(x),v1[i].pb(x);
			}
			if(i==s)v[i].pb(t1),v[i].pb(t2),v1[i].pb(t1),v1[i].pb(t2);
			sort(v1[i].begin(),v1[i].end());v1[i].erase(unique(v1[i].begin(),v1[i].end()),v1[i].end());//离散化
			if(i==s)S=getid(t1,i)+(i-1)*(n1+n2+2),T=getid(t2,i)+(i-1)*(n1+n2+2);//加入起点和终点
		}
		//cout<<S<<" "<<T<<endl;
		built();
		printf("%lld\n",dij());
	}

}

猜你喜欢

转载自blog.csdn.net/qq_40400202/article/details/102553693