[SDOI 2009]Elaxia的路线[拓扑dp][最短路]

题面: https://www.luogu.com.cn/problem/P2149

求两条最短路的最长公共路径


 首先我们肯定要建出两条最短路的交,那么第一个问题是如何判断一条边是不是在最短路径上

我们可以从 4 个点都为源点跑最短路,然后分别获取长度,然后根据式子 $dis(x1,u)+dis(u,v)+dis(v,y1)==dis(x1,y1)$ 来判断边 $(u\rightarrow v)$ 是不是最短路上的边

但是也没有这么简单,根据题意,第一个人的走法是 $(u\rightarrow v)$ 而第二个人的走法是 $(v\rightarrow u)$,这样也算是相遇,但是这种判断方法看起来就 8 太行

解决方法也很简单,把一条边判断两次,第二次判断时把其中一个人的方向转换一下

好,这样我们就建出了一张两条最短路交的 DAG

然后求最长路径那么显然可以 topo dp 一下,做完了

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <cstdlib>
  6 #include <vector>
  7 #include <queue>
  8 #include <cctype>
  9 #define inf 1510
 10 #define ll long long
 11 #define INF 0x7fffffff
 12 #define HINF 0x3f3f3f3f
 13 
 14 namespace chiaro{
 15 
 16 namespace io {
 17     const int SIZE = (1 << 21) + 1;
 18     char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
 19     
 20     #define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
 21     
 22     inline void flush () {
 23         fwrite (obuf, 1, oS - obuf, stdout);
 24         oS = obuf;
 25     }
 26     
 27     inline void putc (char x) {
 28         *oS ++ = x;
 29         if (oS == oT) flush ();
 30     }
 31     
 32     template <class I>
 33     inline void read (I &x) {
 34         for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
 35         for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); 
 36         x *= f;
 37     }
 38     
 39     template <class I>
 40     inline void print (I x) {
 41         if (!x) putc ('0'); 
 42         if (x < 0) putc ('-'), x = -x;
 43         while (x) qu[++ qr] = x % 10 + '0',  x /= 10;
 44         while (qr) putc (qu[qr --]);
 45     }
 46     
 47     struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
 48 }
 49 //using io :: read; using io :: putc; using io :: print;
 50 template <class T> 
 51 inline void read(T& num) {
 52     num = 0; register char c = getchar(), up = c;
 53     while(!isdigit(c)) up = c, c = getchar();
 54     while(isdigit(c)) num = (num << 3) + (num << 1) + (c ^ '0'), c = getchar();
 55     up == '-' ? num = -num : 0;
 56 }
 57 template <class T>
 58 inline void read(T& a,T& b) {read(a); read(b);}
 59 template <class T>
 60 inline void read(T& a,T& b, T& c) {read(a); read(b); read(c);}
 61 
 62 inline void setting() {
 63 #ifdef ONLINE_JUDGE
 64     freopen("travel.in", "r", stdin);
 65     freopen("travel.out", "w", stdout);
 66 #endif
 67 }
 68 
 69 struct edge {
 70     int to;
 71     int val;
 72     edge* nxt;
 73 };
 74 
 75 struct Point {
 76     int x;
 77     int y;
 78 };
 79 
 80 struct Node {
 81     int dis;
 82     int pos;
 83     inline bool operator < (const Node& nxt) const {
 84         return dis > nxt.dis;
 85     }
 86     Node() {}
 87     Node(int dis, int pos) {
 88         this->dis = dis;
 89         this->pos = pos;
 90     }
 91 };
 92 
 93 int n, m;
 94 int ans;
 95 int dis[5][inf];
 96 int deg[inf], maxlen[inf];
 97 bool vis[inf];
 98 Point s, t;
 99 edge *g1[inf * inf], *g2[inf * inf];
100 std::queue <int> Q;
101 std::priority_queue <Node, std::vector <Node>> P;
102 
103 inline void connect(int from, int to, int val, edge **g) {
104 //    printf("%d => %d: %d\n", from, to, val);
105     static edge pool[inf * inf << 1];
106     static edge* p = pool;
107     p->to = to;
108     p->val = val;
109     p->nxt = g[from];
110     g[from] = p; ++p;
111 }
112 
113 inline void dij(int s, int *dis) {
114     std::fill(vis, vis + 1 + n, 0);
115     std::fill(dis, dis + 1 + n, HINF);
116     P.push(Node(0, s)); dis[s] = 0;
117     while(!P.empty()) {
118         int x = P.top().pos; P.pop();
119         if(vis[x]) continue;
120         vis[x] = 1;
121         for(auto e = g1[x]; e; e = e->nxt) {
122             int y = e->to;
123             if(dis[y] > dis[x] + e->val) {
124                 dis[y] = dis[x] + e->val;
125                 if(vis[y] == 0) P.push(Node(dis[y], y));
126             }
127         }
128     }
129     return;
130 }
131 
132 inline void clear() {
133     std::fill(g2, g2 + 1 + n, nullptr);
134     std::fill(maxlen, maxlen + 1 + n, 0);
135     std::fill(deg, deg + 1 + n, 0);
136     return;
137 }
138 
139 inline void topo() {
140     for(int i = 1; i <= n; i++) {
141         if(deg[i] == 0) Q.push(i);
142     }
143     while(!Q.empty()) {
144         auto x = Q.front(); Q.pop();
145         for(auto e = g2[x]; e; e = e->nxt) {
146             maxlen[e->to] = std::max (maxlen[e->to], maxlen[x] + e->val);
147             if(--deg[e->to] == 0) Q.push(e->to);
148         }
149     }
150     return;
151 }
152 
153 inline void solve(int x1, int y1, int x2, int y2) {
154     clear();
155     for(int i = 1; i <= n; i++) {
156         for(auto e = g1[i]; e; e = e->nxt) {
157             if (dis[x1][i] + e->val + dis[y1][e->to] == dis[1][s.y] && dis[x2][i] + e->val + dis[y2][e->to] == dis[3][t.y]) {
158                 connect(i, e->to, e->val, g2);
159                 ++deg[e->to];
160             }
161         }
162     }
163     topo();
164     for(int i = 1; i <= n; i++) ans = std::max (ans, maxlen[i]);
165     return;
166 }
167 
168 inline signed main () {
169     read(n, m);
170     read(s.x, s.y);
171     read(t.x, t.y);
172     for(int i = 1; i <= m; i++) {
173         int u, v, w; read(u, v, w);
174         connect(u, v, w, g1);
175         connect(v, u, w, g1);
176     }
177     dij(s.x, dis[1]);
178     dij(s.y, dis[2]);
179     dij(t.x, dis[3]);
180     dij(t.y, dis[4]);
181     ans = 0;
182     solve(1, 2, 3, 4);
183     solve(1, 2, 4, 3);
184     printf("%d\n", ans);
185     return 0;
186 }
187 
188 }
189 
190 signed main() {return chiaro::main();}

 

posted @ 2020-08-29 16:18  Chiaro  阅读(196)  评论(0)    收藏  举报