分层图最短路
Posted chiarochinoful
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分层图最短路相关的知识,希望对你有一定的参考价值。
填坑
分层图最短路
板子题
我们可以分成k + 1层
每一层按照题意连边
每相邻的两层间连长度为 0 的合法有向边
比如题目给出 u -> v : w 这条边 , 那么同时可以连 u(dep1) -> v(dep2) : 0 一条边 , 表示第一层点 u 可以花费 0 到第二层点v
这样很显然能看出 , 从一层到下一层 , 就等于是坐了一次免费的飞机
然后跑一边 Dij 就没了
Code:
1 //#pragma GCC optimize(2) 2 #include<cmath> 3 #include<cstdio> 4 #include<cstring> 5 #include<cstdlib> 6 #include<queue> 7 #include<vector> 8 #include<iostream> 9 #include<algorithm> 10 #define N 510 11 #define debug 1 12 #define osu auto 13 #define FILETEST 1 14 #define inf 2500010 15 #define ll long long 16 #define ha 998244353 17 #define INF 0x7fffffff 18 #define pii std::pair <int, int> 19 #define INF_T 9223372036854775807 20 #define APART puts("----------------------") 21 #define DEBUG printf("%s %d ",__FUNCTION__,__LINE__) 22 23 namespace chino{ 24 25 inline void setting(){ 26 #if FILETEST 27 freopen("_test.in", "r", stdin); 28 freopen("_test.me.out", "w", stdout); 29 #endif 30 return; 31 } 32 33 inline int read(){ 34 register char c = getchar(), up = c; register int num = 0; 35 while(c < ‘0‘ || c > ‘9‘) up = c, c = getchar(); 36 while(c >= ‘0‘ && c <= ‘9‘) num = (num << 3) + (num << 1) + (c ^ ‘0‘), c = getchar(); 37 return up == ‘-‘ ? -num : num; 38 } 39 40 int n, m, k; 41 int s, t; 42 int index; 43 int dis[inf], vis[inf]; 44 int head[inf]; 45 struct Edge{ 46 int to; 47 int val; 48 int next; 49 }e[inf << 1]; 50 struct Node{ 51 int dis; 52 int pos; 53 inline bool operator<(const Node &next) const { 54 return dis > next.dis; 55 } 56 }; 57 std::priority_queue <Node, std::vector <Node> > P; 58 59 inline void AddEdge(int from, int to, int val){ 60 ++index; 61 e[index].to = to; 62 e[index].val = val; 63 e[index].next = head[from]; 64 head[from] = index; 65 return; 66 } 67 68 inline void dij(int s){ 69 P.push(Node{0, s}); 70 memset(dis, 10, sizeof dis); 71 dis[s] = 0; 72 while(!P.empty()){ 73 int x = P.top().pos; P.pop(); 74 if(vis[x]) continue; 75 vis[x] = 1; 76 for(int i = head[x]; i; i = e[i].next){ 77 int y = e[i].to; 78 if(dis[y] > dis[x] + e[i].val){ 79 dis[y] = dis[x] + e[i].val; 80 if(vis[y] == 0) P.push(Node{dis[y], y}); 81 } 82 } 83 } 84 return; 85 } 86 87 inline int main(){ 88 memset(e, 0, sizeof e); 89 n = read(), m = read(), k = read(); 90 s = read(), t = read(); 91 for(int i = 1; i <= m; i++){ 92 int u = read(); 93 int v = read(); 94 int w = read(); 95 for(int j = 0; j <= k; j++){ 96 AddEdge(u + j * n, v + j * n, w); 97 AddEdge(v + j * n, u + j * n, w); 98 if(j == 0) continue; 99 AddEdge(u + (j - 1) * n, v + j * n, 0); 100 AddEdge(v + (j - 1) * n, u + j * n, 0); 101 } 102 } 103 dij(s); 104 int ans = INF; 105 for(int i = 0; i <= k; i++) // 可能并不会用光 k 次免费坐飞机的机会 106 ans = std::min (ans, dis[t + i * n]); 107 printf("%d ", ans); 108 return 0; 109 } 110 111 }//namespace chino 112 113 signed main(){return chino::main();}
在买入或卖出之外的时刻是可以在图上随便游走的
所以每一层点之间的边权是 0
分三层 , 从第一层掉到第二层表示买入了 , 从第二层掉到第三层表示卖出了
所以一二层间每个点与自己连一条 -cost 的边 , 表示花费了 cost 的软妹币
二三层间自己与自己连 cost 的边 , 表示卖出从而得到了 cost 的软妹币
这样SPFA一遍最长路
然而有的情况可能买入卖出后得到了负收益
那这种情况显然不如不做这笔生意
Code:
1 //#pragma GCC optimize(2) 2 #include<cmath> 3 #include<cstdio> 4 #include<cstring> 5 #include<cstdlib> 6 #include<queue> 7 #include<vector> 8 #include<iostream> 9 #include<algorithm> 10 #define N 510 11 #define debug 1 12 #define osu auto 13 #define FILETEST 1 14 #define inf 2000010 15 #define ll long long 16 #define ha 998244353 17 #define INF 0x7fffffff 18 #define pii std::pair <int, int> 19 #define INF_T 9223372036854775807 20 #define APART puts("----------------------") 21 #define DEBUG printf("%s %d ",__FUNCTION__,__LINE__) 22 23 namespace chino{ 24 25 inline void setting(){ 26 #if FILETEST 27 freopen("_test.in", "r", stdin); 28 freopen("_test.me.out", "w", stdout); 29 #endif 30 return; 31 } 32 33 inline int read(){ 34 register char c = getchar(), up = c; register int num = 0; 35 while(c < ‘0‘ || c > ‘9‘) up = c, c = getchar(); 36 while(c >= ‘0‘ && c <= ‘9‘) num = (num << 3) + (num << 1) + (c ^ ‘0‘), c = getchar(); 37 return up == ‘-‘ ? -num : num; 38 } 39 40 int n, m; 41 int index; 42 int s, t; 43 int dis[inf], vis[inf]; 44 int cost[inf]; 45 int head[inf]; 46 struct Edge{ 47 int to; 48 int val; 49 int next; 50 }e[inf << 1]; 51 std::queue <int> Q; 52 53 inline void AddEdge(int from, int to, int val){ 54 ++index; 55 e[index].to = to; 56 e[index].val = val; 57 e[index].next = head[from]; 58 head[from] = index; 59 return; 60 } 61 62 inline void spfa(int s){ 63 std::fill(dis + 1, dis + 1 + n + n + n, -(INF >> 1)); 64 Q.push(s); 65 dis[s] = 0, vis[s] = 1; 66 while(!Q.empty()){ 67 int x = Q.front(); Q.pop(); 68 vis[x] = 0; 69 for(int i = head[x]; i; i = e[i].next){ 70 int y = e[i].to; 71 if(dis[y] < dis[x] + e[i].val){ 72 dis[y] = dis[x] + e[i].val; 73 if(vis[y] == 0){ 74 vis[y] = 1; 75 Q.push(y); 76 } 77 } 78 } 79 } 80 return; 81 } 82 83 inline int main(){ 84 n = read(), m = read(); 85 for(int i = 1; i <= n; i++){ 86 cost[i] = read(); 87 AddEdge(i, i + n, -cost[i]); 88 AddEdge(i + n, i + n + n, cost[i]); 89 } 90 for(int i = 1; i <= m; i++){ 91 int u = read(); 92 int v = read(); 93 int w = read() - 1; 94 AddEdge(u, v, 0); 95 AddEdge(u + n, v + n, 0); 96 AddEdge(u + n + n, v + n + n, 0); 97 if(w == 0) continue; 98 AddEdge(v, u, 0); 99 AddEdge(v + n, u + n, 0); 100 AddEdge(v + n + n, u + n + n, 0); 101 } 102 s = 1, t = n + n + n; 103 spfa(s); 104 printf("%d ", std::max (0, dis[t])); 105 return 0; 106 } 107 108 }//namespace chino 109 110 signed main(){return chino::main();}
以上是关于分层图最短路的主要内容,如果未能解决你的问题,请参考以下文章