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 }
View Code

 

 

posted @ 2017-03-21 08:50  Splay  阅读(191)  评论(0编辑  收藏  举报