【JZOJ3086】【洛谷P3831】回家【最短路】

题目大意:

题目链接:

JZOJ:https://jzoj.net/senior/#main/show/3086
洛谷:https://www.luogu.org/problemnew/show/P3831

moreDmoreD城的城市轨道交通建设终于全部竣工,由于前期规划周密,建成后的轨道交通网络由 2n2n条地铁线路构成,组成了一个nnnn横的交通网。如下图所示,这2n2n条线路每条线路都包含nn个车站,而每个车站都在一组纵横线路的交汇处。
出于建设成本的考虑,并非每个车站都能够进行站内换乘,能够进行站内换乘的地铁站共有mm 个,在下图中,标上方块标记的车站为换乘车站。已知地铁运行11站需要22分钟,而站内换乘需要步行11分钟。 你的最后一个作业就是算出,在不中途出站的前提下,从学校回家最快需要多少时间(等车时间忽略不计)。
在这里插入图片描述


思路:

每个点拆成横点和竖点,之间连一条长度为11的边作为转站时间。
若两个点在同一行或同一列,之间连上长度的22倍的边。
跑最短路即可。注意连边时需要排序连边,保证复杂度。
时间复杂度:O(n logn)O(n\ logn)


代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#define mp make_pair
using namespace std;

const int N=200010;
int n,m,S,T,tot,head[N],dis[N],id[N];
bool vis[N];
priority_queue<pair<int,int> > q;

struct edge
{
	int to,dis,next;
}e[N*4];

struct station
{
	int x,y;
}a[N];

void add(int from,int to,int dis)
{
	e[++tot].to=to;
	e[tot].dis=dis;
	e[tot].next=head[from];
	head[from]=tot;
}

bool cmp1(int x,int y)
{
	return a[x].x<a[y].x||(a[x].x==a[y].x&&a[x].y<a[y].y);
}

bool cmp2(int x,int y)
{
	return a[x].y<a[y].y||(a[x].y==a[y].y&&a[x].x<a[y].x);
}

void dij()
{
	memset(dis,0x3f3f3f3f,sizeof(dis));
	q.push(mp(0,S));
	dis[S]=0;
	vis[S]=1;
	while (q.size())
	{
		int u=q.top().second;
		q.pop();
		for (int i=head[u];~i;i=e[i].next)
		{
			int v=e[i].to;
			if (dis[v]>dis[u]+e[i].dis)
			{
				dis[v]=dis[u]+e[i].dis;
				if (!vis[v])
				{
					q.push(mp(-dis[v],v));
					vis[v]=1;
				}
			}
		}
	}
}

int main()
{
	memset(head,-1,sizeof(head));
	scanf("%d%d",&n,&m);
	m+=2;
	for (int i=1;i<=m-2;i++)
	{
		scanf("%d%d",&a[i].x,&a[i].y);
		id[i]=i;
	}
	S=m-1; T=m;
	scanf("%d%d",&a[S].x,&a[S].y); id[S]=S;
	scanf("%d%d",&a[T].x,&a[T].y); id[T]=T;
	sort(id+1,id+1+m,cmp1);
	for (int i=1;i<m;i++)
		if (a[id[i]].x==a[id[i+1]].x)
		{
			add(id[i],id[i+1],(a[id[i+1]].y-a[id[i]].y)*2);
			add(id[i+1],id[i],(a[id[i+1]].y-a[id[i]].y)*2);
		}
	sort(id+1,id+1+m,cmp2);
	for (int i=1;i<m;i++)
		if (a[id[i]].y==a[id[i+1]].y)
		{
			add(id[i]+m,id[i+1]+m,(a[id[i+1]].x-a[id[i]].x)*2);
			add(id[i+1]+m,id[i]+m,(a[id[i+1]].x-a[id[i]].x)*2);
		}
	add(T,T+m,0); add(T+m,T,0);
	add(S,S+m,0); add(S+m,S,0);
	for (int i=1;i<=m-2;i++)
		add(i,i+m,1),add(i+m,i,1);
	dij();
	if (min(dis[T],dis[T+m])<1e9) printf("%d\n",min(dis[T],dis[T+m]));
		else printf("-1\n");
	return 0;
}
posted @ 2019-01-23 21:23  全OI最菜  阅读(133)  评论(0编辑  收藏  举报