[SHOI2012]回家的路

回家的路

时间限制:1s 空间限制:512MB
输入文件:gohome.in 输出文件:gohome.out

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

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

输出格式
只有一行,即 Serenade 在合理选择线路的情况下,回家所需要的时间。
如果 Serenade 无法在不出站换乘的情况下回家,请输出-1。

样例数据
input1

2 1
1 2
1 1 2 2

output1

5

input2

6 9
2 1
2 5
3 2
4 4
5 2
5 6
6 1
6 3
6 4
1 1 4 6

output2

27

input3

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

output3

26

数据规模与约定
对于 30%的数据,n≤50,m≤1000n≤50,m≤1000;
对于 60%的数据,n≤500,m≤2000n≤500,m≤2000;
对于 100%的数据,n≤20000,m≤100000n≤20000,m≤100000;

题解
因为公交车有两种走法,上下走和左右走,所以分别建图(只需要管可以换乘的点以及起点和终点),然后换乘点上下图再连线,距离是1,起点和终点的上下图连线是0.
然后用SPFA跑一遍最短路就可以了。具体注释看代码。

代码
代码借鉴了某位大佬,因为我还没怎么搞懂vector的用法

    #include<bits/stdc++.h>
    #define ll long long
    #define memset(x) memset(x, 0, sizeof(x))
    using namespace std;
    vector< pair<int,int> >E[300005];//从今天开始学着用vector 
    void add(int from,int to,int val){
        E[from].push_back(make_pair(to,val));//在数组的最后添加一个数据
        E[to].push_back(make_pair(from,val));//表示from到to的距离是val,双向建 
        //需要pair做参数的位置,可以直接调用make_pair生成pair对象。 
    }
    struct psx {int x,y,id;}sta[300005];
    bool cmp1(psx a,psx b){
        if(a.x == b.x) return a.y < b.y;
        return a.x < b.x;
    }
    bool cmp2(psx a,psx b){
        if(a.y == b.y) return a.x < b.x;
        return a.y < b.y;
    }
    int n,m;
    queue<int> q;
    int dis[300005]; 
    bool vis[300005];//是否在队列中 
    void spfa(){//模板
        for(int i = 1; i <= 2*m+4; i++)
    		dis[i] = 201908230;
        dis[m+1] = 0;
    	vis[m+1] = 1; 
    	q.push(m+1);
        while(!q.empty()){
            int now = q.front();
    		q.pop(); vis[now] = 0; 
            for(int i = 0; i < E[now].size(); i++) {
                int to  = E[now][i].first;
    			int val = E[now][i].second;
                if( dis[to] > dis[now]+val) {
                    dis[to] = dis[now]+val;
                    if(!vis[to]) { vis[to]=1; q.push(to);}
                }
            }
        }
    }
    int main()
    {
    	freopen("gohome.in","r",stdin);
    	freopen("gohome.out","w",stdout);
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= m+2; i++){
            scanf("%d%d", &sta[i].x, &sta[i].y);
            sta[i].id=i;//i记录转站点的序号
            //m+1是起点,m+2是终点 
        }
        sort(sta+1, sta+m+3, cmp1);//按照x建 
        for(int i = 1; i < m+2;i++)
        	if(sta[i].x == sta[i+1].x)
    			add(sta[i].id, sta[i+1].id, 2*(sta[i+1].y-sta[i].y));
    	//建立上层图左右结构 
        sort(sta+1, sta+m+3, cmp2);//按照y建 
        for(int i = 1; i < m+2; i++)
        	if(sta[i].y == sta[i+1].y)
    			add(sta[i].id+m+2, sta[i+1].id+m+2, 2*(sta[i+1].x-sta[i].x));
    	//建立下层图上下结构 
        for(int i = 1; i <= m; i++)
        	add(i, i+m+2, 1);
        //上下图之间建立1的距离,转站的花费 
        add(m+1, m*2+3, 0);//起点的上下图距离为0 
    	add(m+2, m*2+4, 0);//终点的上下图距离为0 
        spfa();//求单点距离,起点到其他点 
        if(dis[m+2] == 201908230){
            puts("-1");
            return 0;
        }
        printf("%d\n", dis[m+2]);
    }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值