[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();}

浙公网安备 33010602011771号