BZOJ 3955 Surely You Congest 解题报告
首先,我们可以求出源为 $1$ 号点的最短路图以及各个点到 $1$ 号点的最短路。
然后我们考虑那些距离不同的点,是一定不会发生拥堵现象的。
然后我们就只需要考虑那些距离相同的点,就相当于做一个最大流嘛。
假设考虑与 $1$ 号节点距离为 $d$ 的点,那怎么连边,怎么设置源和汇呢?
- 源为 $1$ 号节点,新开一个 $n+1$ 号节点作为汇。
- 对于所有满足 $dist(1, x) + w(x,y) = dist(1, y)$ 的 $x,y$ 建一条 $x\rightarrow y$ 的边,容量为 $1$。
- 如果某个点 $x$ 与 $1$ 号节点距离恰好为 $d$,建一条 $x\rightarrow T$ 的边,容量为这个点上车辆的数目。
然后把所有距离下的最大流加起来,就是答案了。
复杂度看起来有点高,不过加点优化应该还是能跑过去的。
我加了一个优化:如果与 $1$ 号节点距离为 $d$ 的车辆只有 $1$ 辆,那么最大流就是 $1$,就不用去跑网络流了。
感觉效果还不错。
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 typedef long long LL; 8 #define C 2000 + 5 9 #define N 50000 + 5 10 #define M 400000 + 5 11 #define SIZE 10000000 + 5 12 #define INF 0x7fffffff 13 14 int n, m, c, S, T, tot, _tot, ans; 15 int A[C]; 16 int Head[N], _Head[N], Inq[N]; 17 int Dis[N], _Dis[N]; 18 int E[M][3]; 19 int q[SIZE]; 20 21 struct Edge 22 { 23 int next, node, flow, w; 24 }h[M], _h[M]; 25 26 inline void addedge(int u, int v, int fl, int w) 27 { 28 h[++ tot].next = Head[u], Head[u] = tot; 29 h[tot].node = v, h[tot].flow = fl, h[tot].w = w; 30 h[++ tot].next = Head[v], Head[v] = tot; 31 h[tot].node = u, h[tot].flow = 0, h[tot].w = w; 32 } 33 34 inline bool SPFA(int S) 35 { 36 for (int i = S; i <= T; i ++) 37 Dis[i] = INF, Inq[i] = 0; 38 int l = 1, r = 1; 39 Dis[S] = 0, q[1] = S, Inq[S] = 1; 40 while (l <= r) 41 { 42 int z = q[l ++]; 43 Inq[z] = 0; 44 for (int i = Head[z]; i; i = h[i].next) 45 { 46 int d = h[i].node, p = h[i].flow, w = h[i].w; 47 if (!p) continue ; 48 if (Dis[d] > Dis[z] + w) 49 { 50 Dis[d] = Dis[z] + w; 51 if (!Inq[d]) 52 { 53 q[++ r] = d; 54 Inq[d] = r; 55 } 56 } 57 if (Inq[d] && Dis[d] < Dis[q[l]]) 58 { 59 int u = Inq[d], v = q[l]; 60 q[l] = d, q[u] = v; 61 Inq[d] = l, Inq[v] = u; 62 } 63 } 64 } 65 return Dis[T] != INF; 66 } 67 68 inline void Copy() 69 { 70 _tot = tot; 71 for (int i = S; i <= T; i ++) 72 _Head[i] = Head[i], _Dis[i] = Dis[i]; 73 for (int i = 2; i <= tot; i ++) 74 _h[i] = h[i]; 75 } 76 77 inline void Restore() 78 { 79 tot = _tot; 80 for (int i = S; i <= T; i ++) 81 Head[i] = _Head[i]; 82 for (int i = 2; i <= _tot; i ++) 83 h[i] = _h[i]; 84 } 85 86 inline bool cmp(int u, int v) 87 { 88 return Dis[u] < Dis[v]; 89 } 90 91 inline int dinic(int z, int inflow) 92 { 93 if (z == T || !inflow) return inflow; 94 int ret = inflow, flow; 95 for (int i = Head[z]; i; i = h[i].next) 96 { 97 int d = h[i].node, p = h[i].flow; 98 if (Dis[d] != Dis[z] + 1) continue ; 99 flow = dinic(d, min(ret, p)); 100 ret -= flow; 101 h[i].flow -= flow, h[i ^ 1].flow += flow; 102 if (!ret) return inflow; 103 } 104 if (ret == inflow) Dis[z] = -1; 105 return inflow - ret; 106 } 107 108 int main() 109 { 110 #ifndef ONLINE_JUDGE 111 freopen("3955.in", "r", stdin); 112 freopen("3955.out", "w", stdout); 113 #endif 114 115 scanf("%d%d%d", &n, &m, &c); 116 S = 1, T = n + 1; 117 for (int i = 1; i <= m; i ++) 118 { 119 int u, v, w; 120 scanf("%d%d%d", &u ,&v, &w); 121 E[i][0] = u, E[i][1] = v, E[i][2] = w; 122 addedge(u, v, 1, w); 123 addedge(v, u, 1, w); 124 } 125 SPFA(1); 126 for (int i = 1; i <= c; i ++) 127 scanf("%d", A + i); 128 sort(A + 1, A + c + 1, cmp); 129 tot = 1; 130 memset(Head, 0, sizeof(Head)); 131 for (int i = 1; i <= m; i ++) 132 { 133 if (Dis[E[i][0]] + E[i][2] == Dis[E[i][1]]) 134 addedge(E[i][0], E[i][1], 1, 1); 135 if (Dis[E[i][1]] + E[i][2] == Dis[E[i][0]]) 136 addedge(E[i][1], E[i][0], 1, 1); 137 } 138 Copy(); 139 int l = 1, r; 140 for (; l <= c; l = r + 1) 141 { 142 for (r = l; r < c && _Dis[A[r + 1]] == _Dis[A[l]]; r ++) ; 143 if (r == l) ans ++; 144 else 145 { 146 Restore(); 147 for (int i = l; i <= r; i ++) 148 addedge(A[i], T, 1, 1); 149 while (SPFA(S)) 150 ans += dinic(S, INF); 151 } 152 } 153 printf("%d\n", ans); 154 155 #ifndef ONLINE_JUDGE 156 fclose(stdin); 157 fclose(stdout); 158 #endif 159 return 0; 160 }