[CSU 1808: 地铁] Dijkstra

[CSU 1808: 地铁] Dijkstra

题目链接[CSU 1808: 地铁]
题意描述:ICPCCamp 有 n 个地铁站,用 1,2,,n编号。 m 段双向的地铁线路连接 n 个地铁站,其中第 i 段地铁属于 ci 号线,位于站 ai,bi 之间,往返均需要花费 ti 分钟(即从 ai bi 需要 ti 分钟,从 bi ai 也需要 ti 分钟)。
众所周知,换乘线路很麻烦。如果乘坐第 i 段地铁来到地铁站s,又乘坐第 j 段地铁离开地铁站 s,那么需要额外花费 |cicj| 分钟。注意,换乘只能在地铁站内进行。
Bobo 想知道从地铁站 1 到地铁站n所需要花费的最小时间。 (2n105,1m105,1ai,bi,cin,1ti109)
解题思路
很明显,这是一个最短路问题。但是不能单独的以顶点为状态进行松弛操作了。因为还要考虑 |cicj| 。所以用两种做法。

  • 第一种做法是以顶点编号 u 和该顶点上一条边的c值为状态进行松弛操作,这个时候需要用 map 进行对有序二元组 <u,c> <script type="math/tex" id="MathJax-Element-7093"> </script>进行映射一下。
  • 第二种做法是以边的编号 e 为状态进行松弛操作。因为边的数目也不是很多, 也就是2m,所以也不会超时。

显然,第二种做法更加简单快捷。

/**
 * 做法一:以顶点编号u和该顶点上一条边的c值为状态进行松弛操作
 */
#include <map>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int MAXN = 1e5 + 5;
const int MAXE = 1e5 + 5;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;

struct Edge {
    int v, w, c, next;
    Edge() {}
    Edge(int v, int c, int w, int next) : v(v), c(c), w(w), next(next) {}
} edges[MAXE << 1];
int N, M, head[MAXN], ESZ;
map<PII, int> Hash;
int tot;
void init() {
    ESZ = 0;
    tot = 0;
    Hash.clear();
    memset(head, -1, sizeof(head));
}
void add_edge(int u, int v, int c, int w) {
    edges[ESZ] = Edge(v, c, w, head[u]);
    head[u] = ESZ++;
}

struct Dij {
    struct QNode {
        int u, c;
        LL w;
        QNode() {}
        QNode(int u, int c, LL w) : u(u), c(c), w(w) {}
        bool operator > (const QNode& e)const {
            return w > e.w;
        }
    } cur;

    priority_queue<QNode, vector<QNode>, greater<QNode> > Q;
    LL run() {
        int u, v, c, w, delta, ku, kv;
        LL ret = INF;
        vector<LL> cost(tot + 1, INF);
        vector<bool> vis(tot + 1, false);
        Q.push(QNode(1, -1, 0));
        ku = Hash[make_pair(1, -1)];
        cost[ku] = 0;
        while(!Q.empty()) {
            cur = Q.top();
            Q.pop();
            u = cur.u;
            ku = Hash[make_pair(u, cur.c)];
            if(u == N) {
                ret = min(ret, cost[ku]);
            }
            if(vis[ku]) continue;
            vis[ku] = true;
            for(int i = head[u]; ~i; i = edges[i].next) {
                v = edges[i].v, c = edges[i].c, w = edges[i].w;
                kv = Hash[make_pair(v, c)];
                if(~cur.c) delta = abs(cur.c - c);
                else delta = 0;
                if(!vis[kv] && cost[kv] > cost[ku] + w + delta) {
                    cost[kv] = cost[ku] + w + delta;
                    Q.push(QNode(v, c, cost[kv]));
                }
            }
        }
        return ret;
    }
} dij;
int main() {
//    freopen("input.txt", "r", stdin);
    int u, v, c, w;
    while(~scanf("%d %d", &N, &M)) {
        init();
        Hash[make_pair(1, -1)] = ++tot;
        for(int i = 0; i < M; i++) {
            scanf("%d %d %d %d", &u, &v, &c, &w);
            add_edge(u, v, c, w);
            add_edge(v, u, c, w);
            if(!Hash[make_pair(u, c)]) Hash[make_pair(u, c)] = ++tot;
            if(!Hash[make_pair(v, c)]) Hash[make_pair(v, c)] = ++tot;
        }
        LL ans = dij.run();
        printf("%lld\n", ans);
    }
    return 0;
}
/**
 * 做法二:以边的编号e为状态进行松弛操作
 */
#include <map>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int MAXN = 1e5 + 5;
const int MAXE = 1e5 + 5;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;

struct Edge {
    int v, w, c, next;
    Edge() {}
    Edge(int v, int c, int w, int next) : v(v), c(c), w(w), next(next) {}
} edges[MAXE << 1];
int N, M, head[MAXN], ESZ;
void init() {
    ESZ = 0;
    memset(head, -1, sizeof(head));
}
void add_edge(int u, int v, int c, int w) {
    edges[ESZ] = Edge(v, c, w, head[u]);
    head[u] = ESZ++;
}
struct Dij {
    struct QNode {
        int e;
        LL w;
        QNode() {}
        QNode(int e, LL w) : e(e), w(w) {}
        bool operator > (const QNode& x)const {
            return w > x.w;
        }
    } cur;
    priority_queue<QNode, vector<QNode>, greater<QNode> > Q;
    LL cost[MAXE << 1];
    bool vis[MAXE << 1];
    LL run() {
        int u, w, e, delta;
        LL ret = INF;
        memset(cost, 0x3f, sizeof(cost));
        memset(vis, false, sizeof(vis));
        for(int i = head[1]; ~i; i = edges[i].next) {
            cost[i] = edges[i].w;
            Q.push(QNode(i, cost[i]));
        }
        while(!Q.empty()) {
            cur = Q.top();
            Q.pop();
            e = cur.e;
            u = edges[e].v;
            if(vis[e]) continue;
            vis[e] = true;
            if(u == N) ret = min(ret, cost[e]);
            for(int i = head[u]; ~i; i = edges[i].next) {
                w = edges[i].w;
                delta = abs(edges[e].c - edges[i].c);
                if(!vis[i] && cost[i] > cost[e] + w + delta) {
                    cost[i] = cost[e] + w + delta;
                    Q.push(QNode(i, cost[i]));
                }
            }
        }
        return ret;
    }
} dij;
int main() {
//    freopen("input.txt", "r", stdin);
    int u, v, c, w;
    while(~scanf("%d %d", &N, &M)) {
        init();
        for(int i = 0; i < M; i++) {
            scanf("%d %d %d %d", &u, &v, &c, &w);
            add_edge(u, v, c, w);
            add_edge(v, u, c, w);
        }
        LL ans = dij.run();
        printf("%lld\n", ans);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值