P3831 [SHOI2012]回家的路 (分层图最短路)

题目链接

将每个点拆分乘两个点,一个是横向的,一个是纵向的,如果这个点是站点,那么,对于这个点的横向和纵向之间连一条边权为 1 的边,然后,对于横向之间进行连边, 对于纵向之间进行连边, 但如果每个点都这样的话, 内存肯定是要炸的。 可以知道,这个题中,对我们有用的就只有各个站点和起点终点。
所以,我们要排序

#include <bits/stdc++.h>
const int maxn = 200050;
const int maxm = 10000050; //边数,往大的开
const int inf = 0x3f3f3f3f;
using namespace std;
typedef long long ll;

struct point{
    int x, y;
    int xu;
}p[maxn];
int b[maxn], c[maxn];
bool cmpx(int qian, int hou){       //按x排序
    if(p[qian].x == p[hou].x)   //x相等  y也要排个序
        return p[qian].y < p[hou].y;
    return p[qian].x < p[hou].x;
}
bool cmpy(int qian, int hou){       //按y排序
    if (p[qian].y == p[hou].y)   //y相等  x也要排个序
        return p[qian].x < p[hou].x;
    return p[qian].y < p[hou].y;
}
int n, m, s, t;
//1~m  横向    m+1~2m 纵向
struct note{
    int to, w;
    int next;
} e[maxm];
int head[maxn], cnt;
void add(int u, int v, int w){
    cnt++;
    e[cnt].to = v, e[cnt].w = w;
    e[cnt].next = head[u], head[u] = cnt;
}
struct node{
    int pos, dis;
    node(){}
    node(int pos1, int dis1) { pos = pos1, dis = dis1; }
    bool operator<(const node& qian)const{
        return qian.dis < dis;
    }
};
bool vis[maxn];
int dis[maxn];

void DJ(){
    for (int i = 1; i <= 2 * m; i++)
        dis[i] = inf;
    dis[s] = 0;
    priority_queue<node> q;
    q.push(node(s, 0));
    while(!q.empty()){
        node temp = q.top();
        q.pop();
        int u = temp.pos;
        if(vis[u])
            continue;
        vis[u] = true;
        for (int i = head[u]; i; i=e[i].next){
            int v = e[i].to, w = e[i].w;
            if(dis[v] > dis[u] + w){
                dis[v] = dis[u] + w;
                if(!vis[v])
                    q.push(node(v, dis[v]));
            }
        }
    }
    if(dis[t] == inf)
        dis[t] = -1;
    printf("%d\n", dis[t]);
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++){
        scanf("%d%d", &p[i].x, &p[i].y);
        p[i].xu = i;
        b[i] = c[i] = i;
    }
    int x1, y1, x2, y2;
    scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
    p[++m].x = x1, p[m].y = y1, p[m].xu = m, b[m] = c[m] = m, s = m; //将起点添加进去
    p[++m].x = x2, p[m].y = y2, p[m].xu = m, b[m] = c[m] = m, t = m; //将终点添加进去
    sort(b + 1, b + m + 1, cmpx);   //映射排序
    sort(c + 1, c + m + 1, cmpy);   //映射排序
    for (int i = 2; i <= m; i++)
    {
        if (p[b[i]].x == p[b[i - 1]].x)
        { //横向之间
            int u = p[b[i]].xu, v = p[b[i - 1]].xu;
            int w = (p[b[i]].y - p[b[i - 1]].y) * 2;    //计算权值
            add(u, v, w), add(v, u, w);
        }
        if (p[c[i]].y == p[c[i - 1]].y)
        { //纵向之间
            int u = p[c[i]].xu + m, v = p[c[i - 1]].xu + m;
            int w = (p[c[i]].x - p[c[i - 1]].x) * 2;    // 计算权值
            add(u, v, w), add(v, u, w);
        }
    }
    for (int i = 1; i <= m - 2; i++)
        add(i, i + m, 1), add(i + m, i, 1); //一个点之间的换乘
    add(s, s + m, 0), add(s + m, s, 0);
    add(t, t + m, 0), add(t + m, t, 0);
    DJ();
    return 0;
}
posted @ 2019-08-02 16:39  季之怡  阅读(17)  评论(0编辑  收藏  举报