• 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
    ", ans[i]);
    106     return 0;
    107 }
    View Code

     

  • 相关阅读:
    python字典实现原理-哈希函数-解决哈希冲突方法
    ElasticSearch-倒排索引
    ElasticSearch-核心概念
    MarkdownPad2基础语法
    下载python3.6,进行编译安装,运行django程序
    linux-指令1
    注解和反射
    Htlm和Css
    JAVASE加强
    网络编程
  • 原文地址:https://www.cnblogs.com/-ZZB-/p/6592685.html
Copyright © 2020-2023  润新知