【JZOJ A&B组】回家

Description

moreD城的城市轨道交通建设终于全部竣工,由于前期规划周密,建成后的轨道交通网络由 2n 条地铁线路构成,组成了一个 n 纵 n 横的交通网。如下图所示,这 2n 条线路每条线路都包含 n 个车站,而每个车站都在一组纵横线路的交汇处。

出于建设成本的考虑,并非每个车站都能够进行站内换乘,能够进行站内换乘的地铁站共有 m 个,在下图中,标上方块标记的车站为换乘车站。已知地铁运行 1 站需要 2 分钟,而站内换乘需要步行 1 分钟。 你的最后一个作业就是算出,在不中途出站的前提下,从学校回家最快需要多少时间(等车时间忽略不计)。

Input

第一行有两个整数 n, m。接下去 m 行每行两个整数 x, y,表示第 x 条横向线路与第 y 条纵向线路的交汇站是站内换乘站。接下去一行是四个整数 x1, y1, x2, y2。表示从学校回家时,在第 x1条横向线路与第 y1 条纵向线路的交汇站上车,在第 x2 条横向线路与第 y2 条纵向线路的交汇站下车。

Output

仅一个整数表示在合理选择线路的情况下,回家所需要的最少时间。如果无法在不出站换车的情况下回家则输出-1.

Sample Input

Sample Input 1
6 9
2 1
2 5
3 2
4 4
5 2
5 6
6 1
6 3
6 4
1 1 4 6

Sample Input 2
6 10
2 1
2 5
3 2
4 4
5 2
5 6
6 1
6 3
6 4
6 6
1 1 4 6

Sample Input 3
2 1
1 2
1 1 2 2

Sample Output

Sample Output 1
27

Sample Output 2
26

Sample Output 3
5

Data Constraint

Hint

对于10%的数据m=0

对于 30%的数据,n ≤ 50, m ≤ 1000;

对于 60%的数据,n ≤ 500, m ≤ 2000;

对于 100%的数据,n ≤ 20000, m ≤ 100000;

思路

每一个中转站看做两个点,一个横着连边,一个竖着连边,他们之间连一条权值为1的边。
跑一遍spfa即可

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=800077,inf=0x3f3f3f3f;
int s,t,list[maxn],d[maxn],n,m,cnt;
bool b[maxn];
struct A
{
	int x,y,id;
}a[maxn];
struct E
{
	int to,next,v;
}e[maxn*2];
bool cmp1(A a,A b)
{
    if(a.x==b.x)return a.y<b.y;
    return a.x<b.x;
}
bool cmp2(A a,A b)
{
    if(a.y==b.y)return a.x<b.x;
    return a.y<b.y;
}
void ins(int u,int v,int val)
{
	e[++cnt].to=v; e[cnt].next=list[u]; list[u]=cnt; e[cnt].v=val;
}
void add(int u,int v,int val)
{
	ins(u,v,val); ins(v,u,val);
}
void spfa()
{
	memset(d,0x3f,sizeof(d)); d[s]=0;
	queue<int> q; b[s]=1; q.push(s);
	while(!q.empty())
	{
		int u=q.front(); q.pop(); b[u]=0;
		for(int i=list[u]; i; i=e[i].next)
		{
			int v=e[i].to;
			if(d[v]>d[u]+e[i].v)
			{
				d[v]=d[u]+e[i].v;
				if(!b[v]) b[v]=1,q.push(v);
			}
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m); s=m+1,t=m+2;
	for(int i=1; i<=m+2; i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		a[i].x=x; a[i].y=y; a[i].id=i;
	}
	sort(a+1,a+m+3,cmp1);
    for(int i=1; i<m+2; i++)
    if(a[i].x==a[i+1].x) add(a[i].id,a[i+1].id,2*(a[i+1].y-a[i].y));
    sort(a+1,a+m+3,cmp2);
    for(int i=1; i<m+2; i++)
    if(a[i].y==a[i+1].y) add(a[i].id+m+2,a[i+1].id+m+2,2*(a[i+1].x-a[i].x));
    for(int i=1; i<=m; i++) add(i,i+m+2,1);
    add(m+1,m*2+3,0); add(m+2,m*2+4,0);
    spfa();
    if(d[t]==inf)
    {
        printf("-1"); return 0;
    }
    printf("%d\n",d[t]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值