shoi2012 回家的路

 输入数据

5 4
1 2
2 2
2 5
3 5
1 1
5 5

输出数据

19

 

 

从5号点出发,走到1,代价为2
1换乘,走到7,代价为1
7走到8,代价为2
8换乘,走到2,代价为1
2走到3,代价为6
3换乘走到9,代价为1
9走到10,代价为2
10走到12,代价为4
12走到6,代价为0
总代价为2+1+2+1+6+1+2+4=19

 

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

template <class T>
inline void read(T &x) {
    x = 0;
    char c = getchar();
    bool f = 0;
    for (; !isdigit(c); c = getchar()) f ^= c == '-';
    for (; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
    x = f ? -x : x;
}

template <class T>
inline void write(T x) {
    if (x < 0) {
        putchar('-');
        x = -x;
    }
    T y = 1;
    int len = 1;
    for (; y <= x / 10; y *= 10) ++len;
    for (; len; --len, x %= y, y /= 10) putchar(x / y + 48);
}

const int MAXN = 3e5, MAXM = 3e6;
int n, m, s, t, tot, head[MAXN + 5], dis[MAXN + 5];
bool vis[MAXN + 5];
struct Station {
    int x, y, id;
} a[MAXN + 5];
struct Edge {
    int next, to, dis;
} e[MAXM + 5];
struct Node {
    int val, id;
    inline friend bool operator<(Node x, Node y) {
        return x.val > y.val;
    }
};

inline void addEdge(int u, int v, int w) {
    e[++tot] = (Edge) { head[u], v, w };
    head[u] = tot;
}

inline bool cmpx(Station a, Station b) {//按横坐标排序 
    return a.x == b.x ? a.y < b.y : a.x < b.x;
}

inline bool cmpy(Station a, Station b) {//按纵坐标排序
    return a.y == b.y ? a.x < b.x : a.y < b.y;
}

inline void dijkstra(int s) {//堆优化 dijkstra 
    priority_queue<Node> q;
    memset(dis, 0x3f, sizeof (dis));
    dis[s] = 0;
    q.push((Node) { 0, s });
    for (; !q.empty(); ) {
        int u = q.top().id;
        q.pop();
        if (vis[u]) continue;
        vis[u] = 1;
        for (int v, w, i = head[u]; v = e[i].to, w = e[i].dis, i; i = e[i].next)
            if (dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                if (!vis[v]) q.push((Node) { dis[v], v });
            }
    }
}

int main() {
    read(n);  //N代表矩形大小 
	read(m);  //M个中转点 
    n = m + 2;//加上起点与终点,共N个特殊点 
    s = n - 1, t = n;//起点 和 终点 
    for (int i = 1; i <= n; ++i) 
	{
        read(a[i].x);
		read(a[i].y);
        a[i].id = i;//点的编号 
    }
    sort(a + 1, a + n + 1, cmpx); 
    for (int i = 1; i < n; ++i)
    //对于所有的点(出发点,结束点,中转站) 
        if (a[i].x == a[i + 1].x) 
		{
            addEdge(a[i].id, a[i + 1].id, (a[i + 1].y - a[i].y) << 1);
            addEdge(a[i + 1].id, a[i].id, (a[i + 1].y - a[i].y) << 1);
        } //第一层:横向边 
    sort(a + 1, a + n + 1, cmpy);
    for (int i = 1; i < n; ++i)
        if (a[i].y == a[i + 1].y) 
		{
            addEdge(a[i].id + n, a[i + 1].id + n, (a[i + 1].x - a[i].x) << 1);
            addEdge(a[i + 1].id + n, a[i].id + n, (a[i + 1].x - a[i].x) << 1);
        } //第二层:纵向边 
    for (int i = 1; i <= n - 2; ++i)    
    //对于每个换乘站,自己向自己的一个"分身“进行连边,代价为1 
    //也就是说如果从前是横向移动的话,移动一个换乘站,花上一个代价,就可以纵向移动了
	//反之亦然 
	     addEdge(i, i + n, 1), addEdge(i + n, i, 1);
    //两层之间:改变方向用时 1 
    addEdge(s, s + n, 0);
	addEdge(s + n, s, 0);
    addEdge(t, t + n, 0);
	addEdge(t + n, t, 0);//起点和终点改变方向不需要时间 
    dijkstra(s);//求 s -> t 最短路 
    write(dis[t] == 0x3f3f3f3f ? -1 : dis[t]);//判断是否有解 
    putchar('\n');
    return 0;
}

  

posted @ 2024-04-22 12:03  我微笑不代表我快乐  阅读(8)  评论(0)    收藏  举报