【算法练习】Luogu P3831 [SHOI2012]回家的路(分层图最短路)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pengwill97/article/details/82588111

题意

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

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

题解

分层图最短路。
直接建立矩阵是不行的, n 2 太大了。所以要考虑建图方式。
以为能够转向只能在中转站,考虑到如果起点和终点所在的行和列上,如果没有中转站,是不可能从起点出发或者到达终点的。所以我们只需要对中转站进行建图。对每个中转站行和列上的中转站连边,边权为花费的时间,也就是2倍的曼哈顿距离。
然后起点和行列上的中转站连边,终点和行列上的中转站连边,分层图最短路即可。
分层图的时候,只需要记录到达中转站/终点/起点的最短时间即可,分别考虑换乘(改变方向)和不换乘的情况。

代码

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 1e6+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull MOD = 1610612741;
int head[nmax], tot;
int sx, sy, ex ,ey;
struct edge {
    int to, nxt, w;
}e[nmax << 1];
void add_edge(int u, int v, int w) {
    e[tot].to = v;
    e[tot].nxt = head[u];
    e[tot].w = w;
    head[u] = tot++;
//    printf("debug add %d %d %d \n", u, v, w);
}
struct nope {
    int x, y ,id;
}p[nmax];
bool cmp1(nope a, nope b) {
    if(a.x == b.x)
        return a.y < b.y;
    else
        return a.x < b.x;
}
bool cmp2(nope a, nope b) {
    if(a.y == b.y)
        return a.x < b.x;
    else
        return a.y < b.y;
}
bool cmp3(nope a, nope b) {
    return a.id < b.id;
}
inline int getdist(nope a, nope b) {
    return abs(a.x - b.x) + abs(a.y - b.y);
}
int getway(nope a, nope b) {
    if(a.x == b.x)
        return 0;
    else if(a.y == b.y)
        return 1;
}
int n, m;
int dist[nmax];
bool visit[nmax];
struct node {
    int index;
    int dist;
    int way;
    bool operator < (const node & rhs) const {
        return dist > rhs.dist;
    }
};
priority_queue<node> pq;
int bfs(nope st, nope ed) {
    for(int i = 0; i <= m +1; ++i) {
//        dist[i][0] = dist[i][1] = INF;
//        visit[i][0] = visit[i][1] = false;
        dist[i] = INF;
        visit[i] = false;
    }
    while(!pq.empty()) pq.pop();
    for(int i = head[st.id]; i != -1; i = e[i].nxt) {
        int v = e[i].to;
        int w = e[i].w;
        if(getway(p[st.id], p[v]) == 0) {
            dist[v] = w;
            pq.push(node{v, w, 0});
        } else {
            dist[v] = w;
            pq.push(node{v, w, 1});
        }
    }
    dist[st.id] = 0;
//    visit[st.id] = true;
//    pq.pop(nope{st.id, 0, 0});
//    pq.pop(nope{st.id, 0, 1});
    while(!pq.empty()) {
        node tmp = pq.top();
        pq.pop();
        int u = tmp.index;
        int way = tmp.way;
        if(visit[u])
            continue;
        visit[u] = true;
        if(u == ed.id)
            return tmp.dist;
        for(int i = head[u]; i != -1; i = e[i].nxt) {
            int v = e[i].to;
            int w = e[i].w;
            if(!visit[v]) {
                int thisway = getway(p[u], p[v]);
                if(thisway != way && dist[v] > dist[u] + 1 + w) {
                    dist[v] = dist[u] + 1 + w;
                    pq.push(node{v, dist[v], thisway});
                } else if(thisway == way && dist[v] > dist[u] + w) {
                    dist[v] = dist[u] + w;
                    pq.push(node{v, dist[v], thisway});
                }
            }
        }
    }
    return INF;

}
int main(){
    scanf("%d %d", &n, &m);
    memset(head, -1, sizeof head);
    for(int i = 1; i <= m; ++i) {
        scanf("%d %d", &p[i].x, &p[i].y);
        p[i].id = i;
    }
    scanf("%d %d %d %d", &sx, &sy, &ex, &ey);
    nope ss = nope{sx, sy, 0};
    nope ee = nope{ex, ey, m + 1};
    if(sx == ex || sy == ey) {
        printf("%d\n", 2 * getdist(ss, ee));
    } else {
        bool shave = false, ehave = false;
        p[0] = ss;
        p[m+1] = ee;
        sort(p + 1, p + m + 1, cmp1);
        for(int i = 1; i <= m - 1; ++i) {
            if(p[i].x == p[i + 1].x) {
                int w = 2 * getdist(p[i], p[i+1]);
                add_edge(p[i].id, p[i+1].id, w);
                add_edge(p[i+1].id, p[i].id, w);
            }
        }
        sort(p + 1, p + 1 + m, cmp2);
        for(int i = 1; i <= m; ++i) {
            if(p[i].y == p[i+1].y) {
                int w = 2 * getdist(p[i], p[i+1]);
                add_edge(p[i].id, p[i+1].id, w);
                add_edge(p[i+1].id, p[i].id, w);
            }

            if(p[i].x == sx || p[i].y == sy) {
                add_edge(ss.id, p[i].id, 2 * getdist(p[i], ss));
                add_edge(p[i].id, ss.id, 2 * getdist(p[i], ss));
            }
            if(p[i].x == ex || p[i].y == ey) {
                add_edge(ee.id, p[i].id, 2 * getdist(p[i], ee));
                add_edge(p[i].id, ee.id, 2 * getdist(p[i], ee));

            }
        }
        sort(p + 1, p + 1 + m, cmp3);
        int ans = bfs(ss, ee);
        if(ans == INF)
            printf("-1\n");
        else
            printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/pengwill97/article/details/82588111