1. 程式人生 > >AtCoder ARC061E Snuke's Subway Trip 最短路

AtCoder ARC061E Snuke's Subway Trip 最短路

目錄

(有任何問題歡迎留言或私聊 && 歡迎交流討論哦

Catalog

Problem:傳送門

 原題目描述在最下面。

\(n(1e5)\)個點, \(m(2e5)\)條邊, 每條邊有一個屬性值。經過一條同一屬性值的連續路徑花費為1。問從1到n的最小花費。

Solution:

我的解法

 直接邊最短路搞,然後t的飛起。仔細一想,這樣寫的話有\(1e5\)個點,邊數更是多到飛起,拿命跑啊,不過程式碼我還是放下面。

正解:拆點

 把一條\(u->v\)屬性為\(c\)的路徑,拆成\(u->uc, uc->vc, vc->v\)三條路徑,邊權分別為\(1, 0, 1\)

 然後跑最裸的最短路就行,答案除\(2\)輸出。

why?

 為什麼這樣是對的呢?

 對於一個點連線的許多路徑,從一條走向另一條,如果屬性相同就不需要額外花費。這點怎麼做到的呢?

 比如\(x->y,y->z\)屬性均為\(c\):實際路徑是\(x->yc->z\),經過了yc這個中間點,而且沒有額外的花費。

 答案除\(2\)是因為出發和結束都算了一遍花費。

AC_Code:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <unordered_map>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> pii;

const int INF = 0x3f3f3f3f;
const int MXN = 1e6 + 5;
const int MXT = 2e7 + 6;
const uLL base = 99959;

unordered_map<uLL, int> mp;
int n, m, tn;
int head[MXN], tot;
struct lp {
    int v, c, nex;
}cw[MXT];
int dis[MXT], vis[MXT], fa[MXN];
void add_edge(int u,int v,int w) {
    cw[++tot].v = v;cw[tot].c = w;cw[tot].nex = head[u];
    head[u] = tot;
    cw[++tot].v = u;cw[tot].c = w;cw[tot].nex = head[v];
    head[v] = tot;
}
void dij() {
    priority_queue<pii,vector<pii>,greater<pii> >Q;
    for(int i = 1; i <= n; ++i) dis[i] = INF, vis[i] = 0;
    dis[1] = 0;
    Q.push({dis[1], 1});
    while(!Q.empty()) {
        pii now = Q.top();Q.pop();
        int u = now.se;
        if(vis[u]) continue;
        vis[u] = 1;
        for(int i = head[u]; ~i; i = cw[i].nex) {
            int v = cw[i].v;
            //if(vis[v]) continue;
            if(dis[v] > dis[u] + cw[i].c) {
                dis[v] = dis[u] + cw[i].c;
                Q.push({dis[v], v});
            }
        }
    }
    int ans = dis[tn];
    while(!Q.empty()) Q.pop();
    if(ans == INF) ans = -2;
    printf("%d\n", ans/2);
}
int Fi(int x) {
    return fa[x] == x? x: fa[x] = Fi(fa[x]);
}
int get(int x, int y) {
    uLL tmp = x;
    tmp = tmp * base * base + y * base + x ^ y;
    if(mp[tmp]) return mp[tmp];
    mp[tmp] = ++n;
    return n;
}
int main(int argc, char const *argv[]) {
    while(~scanf("%d%d", &n, &m)) {
        memset(head, -1, sizeof(head));
        tot = -1;
        mp.clear();
        tn = n;
        for(int i = 1; i <= n; ++i) fa[i] = i;
        for(int i = 0, u, v, c, pa, pb, uc, vc; i < m; ++i) {
            scanf("%d%d%d", &u, &v, &c);
            pa = Fi(u), pb = Fi(v);
            fa[pa] = pb;
            uc = get(u, c); vc = get(v, c);
            add_edge(u,uc,1);add_edge(uc,vc,0);add_edge(vc,v,1);
            add_edge(v,vc,1);add_edge(vc,uc,0);add_edge(uc,u,1);
        }
        if(Fi(tn) != Fi(1)){
            printf("-1\n");
            continue;
        }
        dij();
    }
    return 0;
}

TLE_code

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <unordered_map>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> pii;

const int INF = 0x3f3f3f3f;
const int MXN = 1e5 + 5;
const int MXT = 4e5 + 6;

int n, m;
int head[MXN], tot;
struct lp {
    int v, c, nex;
}cw[MXT];
vector<pii> mp[MXN];
int dis[MXT], vis[MXT], fa[MXN];
void add_edge(int u,int v,int w) {
    cw[++tot].v = v;cw[tot].c = w;cw[tot].nex = head[u];
    head[u] = tot;
    cw[++tot].v = u;cw[tot].c = w;cw[tot].nex = head[v];
    head[v] = tot;
}
void dij() {
    priority_queue<pii,vector<pii>,greater<pii> >Q;
    memset(dis, 0x3f, sizeof(dis));
    memset(vis, 0, sizeof(vis));
    for(int i = head[1]; ~i; i = cw[i].nex) {
        dis[i] = 1;
        Q.push({dis[i], i});
    }
    int ans = INF;
    while(!Q.empty()) {
        pii now = Q.top();Q.pop();
        if(vis[now.se]) continue;
        vis[now.se] = 1;
        int u = now.se, a = cw[u].v;
        if(a == n) {
            ans = min(ans, dis[u]);
            break;
        }
        for(int i = head[a]; ~i; i = cw[i].nex) {
            if(vis[i]) continue;
            if(dis[i]>dis[u]+(cw[i].c!=cw[u].c)) {
                dis[i] = dis[u]+(cw[i].c!=cw[u].c);
                Q.push({dis[i], i});
            }
        }
    }
    while(!Q.empty()) Q.pop();
    if(ans == INF) ans = -1;
    printf("%d\n", ans);
}
int Fi(int x) {
    return fa[x] == x? x: fa[x] = Fi(fa[x]);
}
int main(int argc, char const *argv[]) {
    while(~scanf("%d%d", &n, &m)) {
        memset(head, -1, sizeof(head));
        tot = -1;
        for(int i = 1; i <= n; ++i) fa[i] = i;
        for(int i = 0, u, v, c, pa, pb; i < m; ++i) {
            scanf("%d%d%d", &u, &v, &c);
            add_edge(u, v, c);
            pa = Fi(u), pb = Fi(v);
            fa[pa] = pb;
        }
        if(Fi(n) != Fi(1)){
            printf("-1\n");
            continue;
        }
        dij();
    }
    return 0;
}

Problem Description: