[BZOJ1880] [Sdoi2009] Elaxia的路线 (SPFA & 拓扑排序)
Description
最近,Elaxia和w**的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间。Elaxia和w**每天都要奔波于宿舍和实验室之间,他们 希望在节约时间的前提下,一起走的时间尽可能的长。 现在已知的是Elaxia和w**所在的宿舍和实验室的编号以及学校的地图:地图上有N个路 口,M条路,经过每条路都需要一定的时间。
具体地说,就是要求无向图中,两对点间最短路的最长公共路径。
Input
第一行:两个整数N和M(含义如题目描述)。 第二行:四个整数x1、y1、x2、y2(1 ≤ x1 ≤ N,1 ≤ y1 ≤ N,1 ≤ x2 ≤ N,1 ≤ ≤ N),分别表示Elaxia的宿舍和实验室及w**的宿舍和实验室的标号(两对点分别 x1,y1和x2,y2)。 接下来M行:每行三个整数,u、v、l(1 ≤ u ≤ N,1 ≤ v ≤ N,1 ≤ l ≤ 10000),表 u和v之间有一条路,经过这条路所需要的时间为l。 出出出格格格式式式::: 一行,一个整数,表示每天两人在一起的时间(即最长公共路径的长度)。
Output
一行,一个整数,表示每天两人在一起的时间(即最长公共路径的长度)
Sample Input
9 10
1 6 7 8
1 2 1
2 5 2
2 3 3
3 4 2
3 9 5
4 5 3
4 6 4
4 7 2
5 8 1
7 9 1
1 6 7 8
1 2 1
2 5 2
2 3 3
3 4 2
3 9 5
4 5 3
4 6 4
4 7 2
5 8 1
7 9 1
Sample Output
3
HINT
对于30%的数据,N ≤ 100;
对于60%的数据,N ≤ 1000;
对于100%的数据,N ≤ 1500,输入数据保证没有重边和自环。
Source
Solution
补个条件:$m\leq 500000$
如果$dis_{s->u_i}+w_i=dis_{t->v_i}$,那么边$i$才可能成为答案
这些边组成的图一定是一个拓扑图,走一遍最长链即可。
其实主要的坑点在于因为是无向图,所以需要反着做一遍
也就是说,$x_1$->$y_1$和$y_2$->$x_2$的公共路径也可能是答案,也就是说,原题意是错的= =b
1 #include <bits/stdc++.h> 2 using namespace std; 3 struct edge 4 { 5 int v, w, nxt; 6 }e[2000005]; 7 int fst[2][1505], dis[6][1505], q[2105], indeg[1505]; 8 int n, etot, sss1, ttt1, sss2, ttt2; 9 bool inq[1505]; 10 11 void addedge(int *f, int u, int v, int w) 12 { 13 e[++etot] = (edge){v, w, f[u]}, f[u] = etot; 14 } 15 16 bool check(int u, int i) 17 { 18 if(dis[1][u] + e[i].w + dis[2][e[i].v] != dis[1][ttt1]) return false; 19 return dis[3][u] + e[i].w + dis[4][e[i].v] == dis[3][ttt2]; 20 } 21 22 void SPFA(int sss, int *d) 23 { 24 int front = 0, back; 25 memset(d, 63, 6020); 26 q[back = 1] = sss, d[sss] = 0, inq[sss] = true; 27 while(front != back) 28 { 29 int u = q[++front & 2047]; 30 front &= 2047, inq[u] = false; 31 for(int i = fst[0][u]; i; i = e[i].nxt) 32 if(d[e[i].v] > d[u] + e[i].w) 33 { 34 d[e[i].v] = d[u] + e[i].w; 35 if(!inq[e[i].v]) 36 { 37 q[++back & 2047] = e[i].v; 38 back &= 2047, inq[e[i].v] = true; 39 } 40 } 41 } 42 } 43 44 int Topo_sort() 45 { 46 int front = 0, back = 0, ans = 0; 47 for(int i = 1; i <= n; ++i) 48 if(!indeg[i]) q[++back] = i; 49 while(front != back) 50 { 51 int u = q[++front]; 52 for(int i = fst[1][u]; i; i = e[i].nxt) 53 { 54 int v = e[i].v, w = e[i].w; 55 dis[0][v] = max(dis[0][v], dis[0][u] + w); 56 if(!--indeg[e[i].v]) q[++back] = v; 57 } 58 } 59 for(int i = 1; i <= n; ++i) 60 ans = max(ans, dis[0][i]); 61 return ans; 62 } 63 64 int main() 65 { 66 int m, u, v, w, ans; 67 scanf("%d%d", &n, &m); 68 scanf("%d%d%d%d", &sss1, &ttt1, &sss2, &ttt2); 69 for(int i = 1; i <= m; ++i) 70 { 71 scanf("%d%d%d", &u, &v, &w); 72 addedge(fst[0], u, v, w); 73 addedge(fst[0], v, u, w); 74 } 75 SPFA(sss1, dis[1]), SPFA(ttt1, dis[2]); 76 SPFA(sss2, dis[3]), SPFA(ttt2, dis[4]); 77 for(int i = 1; i <= n; ++i) 78 for(int j = fst[0][i]; j; j = e[j].nxt) 79 if(check(i, j)) 80 { 81 addedge(fst[1], i, e[j].v, e[j].w); 82 ++indeg[e[j].v]; 83 } 84 ans = Topo_sort(); 85 memset(fst[1], 0, sizeof(fst[1])); 86 memset(dis[0], 0, sizeof(dis[0])); 87 memset(indeg, 0, sizeof(indeg)); 88 swap(sss2, ttt2); 89 SPFA(sss2, dis[3]), SPFA(ttt2, dis[4]); 90 for(int i = 1; i <= n; ++i) 91 for(int j = fst[0][i]; j; j = e[j].nxt) 92 if(check(i, j)) 93 { 94 addedge(fst[1], i, e[j].v, e[j].w); 95 ++indeg[e[j].v]; 96 } 97 ans = max(ans, Topo_sort()); 98 printf("%d\n", ans); 99 return 0; 100 }