分层图最短路

填坑

分层图最短路


 

[JLOI2011]飞行路线

板子题

我们可以分成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\n",__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\n", ans);
108     return 0;
109 }
110 
111 }//namespace chino
112 
113 signed main(){return chino::main();}

[NOIP2009]最优贸易

在买入或卖出之外的时刻是可以在图上随便游走的

所以每一层点之间的边权是 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\n",__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\n", std::max (0, dis[t]));
105     return 0;
106 }
107 
108 }//namespace chino
109 
110 signed main(){return chino::main();}

 

posted @ 2019-11-09 20:49  ChiaroShiro  阅读(132)  评论(0编辑  收藏  举报