JZOJ 3086. 回家

题目

Description

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


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


 


 

 

Input

第一行有两个整数 n, m。接下去 行每行两个整数 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%的数据,≤ 50, m ≤ 1000


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


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

 

分析

  • 此题的决策为转向,由于只存在横向和纵向两个放学,我们对这两个方向分别建立一层。即一层只连原图横向边,一层只连纵向边。

    对于转向这个决策,将决策前的状态和决策后的状态间连接一条权值为决策代价的边,表示付出该代价转换了状态。

    在本题中,即上下两层对应点连接一条权值为1的边,层内边权均为2.

    然后跑最短路即可。

  • 简单点讲,就是首先将同一横排与竖排上下所有点连边
  • 然后交汇点其实就是一个转向的点
  • 将交汇的点x与y连接跑最短路即可

 

代码

 

 1 #include<iostream>
 2 #include<queue>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define M 800001
 6 #define N 200001
 7 #define inf 0x3f
 8 using namespace std;
 9 struct sb
10 {
11     int x,y,bh;
12 }a[N];
13 struct edge
14 {
15     int next,to,val;
16 }e[M];
17 int n,m;
18 bool cmp(sb a,sb b)
19 {
20     if (a.x==b.x) return a.y<b.y;
21     return a.x<b.x;
22 }
23 bool CMP(sb a,sb b)
24 {
25     if (a.y==b.y) return a.x<b.x;
26     return a.y<b.y;
27 }
28 int h[M],cs=1;
29 void add(int from,int to,int val)
30 {
31     e[cs].to=to;
32     e[cs].next=h[from];  //将它指向对应的下一层 
33     e[cs].val=val;
34     h[from]=cs++;
35 }
36 void ins(int from,int to,int val)
37 {
38     add(from,to,val);
39     add(to,from,val);
40 }
41 queue <int> q;
42 int dis[M];
43 bool v[M];
44 void spfa()
45 {
46     memset(dis,0x3f,sizeof(dis));
47     dis[m+1]=0;
48     v[m+1]=1;
49     q.push(m+1);
50     while (!q.empty())
51     {
52         int x=q.front(); q.pop(); v[x]=0;
53         for (int i=h[x];i;i=e[i].next)
54         {
55             int to=e[i].to,val=e[i].val;
56             if (dis[to]>dis[x]+val)
57             {
58                 dis[to]=dis[x]+val;
59                 if (!v[to])
60                 {
61                     v[to]=1;
62                     q.push(to);
63                 }
64             }
65         }
66     }
67 }
68 int main ()
69 {
70     cin>>n>>m;
71     for (int i=1;i<=m+2;i++)
72     {
73         cin>>a[i].x>>a[i].y;
74         a[i].bh=i;
75     }
76     sort(a+1,a+m+3,cmp);
77     for (int i=1;i<=m+2;i++)
78         if (a[i].x==a[i+1].x) ins(a[i].bh,a[i+1].bh,2*(a[i+1].y-a[i].y));  //将同一行的的x连边,权值为2*(y1-y2) 
79     sort(a+1,a+m+3,CMP);
80     for (int i=1;i<=m+2;i++)
81         if (a[i].y==a[i+1].y) ins(a[i].bh+m+2,a[i+1].bh+m+2,2*(a[i+1].x-a[i].x));   //同一列同上 
82     for (int i=1;i<=m;i++)
83        ins(i,i+m+2,1);   //将转车点x与y连边,权值为1 
84     ins(m+1,2*m+3,0);   ins(m+2,2*m+4,0);   //终点,起点为0 
85     spfa();
86     if (1061109567==dis[m+2])
87         cout<<-1;
88     else
89        cout<<dis[m+2];
90 }

 

posted @ 2019-01-24 16:05  Melted_czj  阅读(114)  评论(0编辑  收藏  举报
body { background-color:whitesmoke; } // 修改背景颜色为半透明 #home,#sideBarMain>div,#blog-sidecolumn>div>div,.catListView{ background-color:rgba(255,255,255,0); } // 修改其他边框的颜色