BZOJ 2750 HAOI 2012 Road 高速公路 最短路
题意:
给出一个有向图,求每条边有多少次作为最短路上的边(任意的起始点)。
范围:n <= 1500, m <= 5005
分析:
一个比较容易想到的思路:以每个点作为起点,做一次SPFA,记f[i]表示从点S到达点i的最短路数,g[i]表示从点i到达点T的最短路数。
那么对于任意一条边,答案就是∑f[u]*g[v]
剩下的问题就是f、g怎么求。
f必须从前面的递推过来,如果前面的没有递推完,那么就不能递推当前点,需要记录每个点可以从多少个点递推过来,这个一次dfs就可以完成。
g可以记忆化搜索来做,先把后继的全部递推完,再递推当前点,就是反过来递推。
程序:
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define REP(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i) 6 #define REP_EDGE(i, a) for (int i = (a); i != -1; i = e[i].nxt) 7 #define mset(a, b) memset(a, b, sizeof(a)) 8 const int maxn = 1505, maxm = 5005, INF = 0x3fffffff, MOD = 1e9+7; 9 typedef long long LL; 10 int n, m; 11 struct Edge 12 { 13 int u, v, w, nxt; 14 Edge (int u = 0, int v = 0, int w = 0, int nxt = 0): u(u), v(v), w(w), nxt(nxt) {} 15 }e[maxm]; 16 int head[maxn], label; 17 int dist[maxn], s_pre[maxn], f[maxn], g[maxn], ans[maxm]; 18 bool vis[maxn]; 19 queue <int> q; 20 21 void ins(int u, int v, int w) { e[++label] = Edge(u, v, w, head[u]), head[u] = label; } 22 23 void SPFA(int S) 24 { 25 REP(i, 1, n) dist[i] = INF, vis[i] = false; 26 vis[S] = true, dist[S] = 0, q.push(S); 27 while (!q.empty()) 28 { 29 int u = q.front(); 30 vis[u] = false, q.pop(); 31 REP_EDGE(i, head[u]) 32 { 33 int v = e[i].v, w = e[i].w; 34 if (dist[v] > dist[u]+w) 35 { 36 dist[v] = dist[u]+w; 37 if (!vis[v]) 38 vis[v] = true, q.push(v); 39 } 40 } 41 } 42 } 43 44 void find_pre(int u) 45 { 46 REP_EDGE(i, head[u]) 47 { 48 int v = e[i].v, w = e[i].w; 49 if (dist[v] == dist[u]+w) 50 { 51 s_pre[v] ++; 52 if (!vis[v]) vis[v] = true, find_pre(v); 53 } 54 } 55 } 56 57 void find_f(int u) 58 { 59 REP_EDGE(i, head[u]) 60 { 61 int v = e[i].v, w = e[i].w; 62 if (dist[v] == dist[u]+w) 63 { 64 f[v] = (f[v]+f[u])%MOD; 65 if (--s_pre[v] == 0) find_f(v); 66 } 67 } 68 } 69 70 void find_g(int u) 71 { 72 g[u] = 1; 73 REP_EDGE(i, head[u]) 74 { 75 int v = e[i].v, w = e[i].w; 76 if (dist[v] == dist[u]+w) 77 { 78 if (!g[v]) find_g(v); 79 g[u] = (g[u]+g[v])%MOD; 80 } 81 } 82 } 83 84 int main() 85 { 86 scanf("%d %d", &n, &m); 87 REP(i, 1, n) head[i] = -1; 88 label = 0; 89 REP(i, 1, m) 90 { 91 int u, v, w; 92 scanf("%d %d %d", &u, &v, &w); 93 ins(u, v, w); 94 } 95 REP(i, 1, n) 96 { 97 SPFA(i); 98 mset(vis, 0), mset(s_pre, 0), mset(f, 0), mset(g, 0); 99 vis[i] = true, find_pre(i); 100 f[i] = 1, find_f(i), find_g(i); 101 REP(j, 1, m) 102 if (dist[e[j].u]+e[j].w == dist[e[j].v]) 103 ans[j] = (ans[j]+((LL)f[e[j].u]*g[e[j].v])%MOD)%MOD; 104 } 105 REP(i, 1, m) printf("%d\n", ans[i]); 106 return 0; 107 }
Nothing is impossible!