分層圖最短路(魔改SPFA)
阿新 • • 發佈:2018-12-01
上週考了道這個因為段考到現在才改完這個 = =
這類問題嘛......算了我先放題目 就比如這個
很顯然問題都是最短路 然後中間可以跳邊走的那種
然後考場上我愣是想到了dp.....
好吧後來我也是在這個基礎上改的 不過這個就是叫分層圖最短路....
做法一:拆點 能免費幾條路就把一個點拆成多少個點 當然還要加1 (原始的) 連的話就是 x 和 y + n 連一個費用為 0 的邊 x 和 y 連一個費用為費用的邊 如果無向圖別忘了反過來
做法二:就像dp一樣 dis[p][k] 為 到達 p 號點 使用 k 條免費路時最小的 dis 值 然後設 p 點到達 b 點 推導就是這樣個東西
這個應該分兩個 但我懶得打了於是就合併了
當然遇到最短路 卡SPFA注意啦 然後我有魔改SPFA 完全不怕!好吧就是加堆啦 = =
其實原本這堆超醜的 如下
inline void push(int p,int k) { ++tot; heap[tot][0] = p; heap[tot][1] = k; o[p][k] = 1; int now = tot; while (now > 1 && dis[heap[now][0]][heap[now][1]] < dis[heap[now >> 1][0]][heap[now >> 1][1]]) swap(heap[now],heap[now >> 1]),now >>= 1; } inline void pop(int &p,int &k) { p = heap[1][0]; k = heap[1][1]; o[p][k] = 0; heap[1][0] = heap[tot][0]; heap[1][1] = heap[tot][1]; --tot; int now = 1; while (now << 1 <= tot && dis[heap[now][0]][heap[now][1]] > dis[heap[now << 1][0]][heap[now << 1][1]] || now << 1 < tot && dis[heap[now][0]][heap[now][1]] > dis[heap[now << 1 | 1][0]][heap[now << 1 | 1][1]]) { int nxt = now << 1; if (nxt < tot && dis[heap[nxt | 1][0]][heap[nxt | 1][1]] < dis[heap[nxt][0]][heap[nxt][1]]) ++nxt; swap(heap[now],heap[nxt]); } }
然後中間判斷距離的就放judge裡面了 看起來好多了 下放程式碼
#include <algorithm> #include <cstring> #include <cstdio> #define MAXN 10010 #define MAXM 100010 using namespace std; struct edge { int ne,to,v; } e[MAXM]; struct queue { int nod,ed; } heap[MAXM]; int first[MAXN],dis[MAXN][22]; int tot; short o[MAXN][22]; inline short judge(queue x,queue y) {return dis[x.nod][x.ed] > dis[y.nod][y.ed];} inline int r() { char q = getchar(); int x = 0,y = 0; while (q < '0' && q != '-' || q > '9') q = getchar(); if (q == '-') ++ y,q = getchar(); while ('0' <= q && q <= '9') x = (x << 3) + (x << 1) + q - (3 << 4),q = getchar(); return y ? -x : x; } inline void add(int x,int y,int z) { e[++tot].ne = first[x]; e[tot].to = y; e[tot].v = z; first[x] = tot; } inline void push(int p,int k) { heap[++tot].ed = k; heap[tot].nod = p; o[p][k] = 1; int now = tot; while (now > 1 && judge(heap[now >> 1],heap[now])) swap(heap[now],heap[now >> 1]),now >>= 1; } inline void pop(int &p,int &k) { p = heap[1].nod; k = heap[1].ed; o[p][k] = 0; heap[1] = heap[tot--]; int now = 1; while (now << 1 <= tot && judge(heap[now],heap[now << 1]) || now << 1 < tot && judge(heap[now],heap[now << 1 | 1])) { int nxt = now << 1; if (nxt < tot && judge(heap[nxt],heap[nxt | 1])) ++nxt; swap(heap[now],heap[nxt]),now = nxt; } } int main() { int n = r(),m = r(),k = r(),s = 1,t = n,x,y,z; while (m--) x = r(),y = r(),z = r(),add(x,y,z),add(y,x,z); memset(dis,0x7f,sizeof(dis)); tot = 0; dis[s][0] = 0; push(s,0); while (tot) { int p,ed; pop(p,ed); for (int a = first[p],b = e[a].to ; a ; a = e[a].ne,b = e[a].to) { if (dis[p][ed] + e[a].v < dis[b][ed]) { dis[b][ed] = dis[p][ed] + e[a].v; if (!o[b][ed]) push(b,ed); } if (ed == k) continue; if (dis[b][ed + 1] > dis[p][ed]) { dis[b][ed + 1] = dis[p][ed]; if (!o[b][ed + 1]) push(b,ed + 1); } } } printf("%d\n",dis[t][k]); return 0; }
雙倍經驗 這題
三倍經驗 開通我校會員專屬