AtCoder ARC061E Snuke's Subway Trip 最短路
阿新 • • 發佈:2018-12-14
目錄
(有任何問題歡迎留言或私聊 && 歡迎交流討論哦
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; }