zoukankan      html  css  js  c++  java
  • 【总结】最短路径条数问题

    例题:NOI2007 社交网络【难度不大,主要就是考察了这个知识点】

    本文进过原作者同意转载,原博主为:  erosun

    原地址:http://www.cnblogs.com/acxblog/p/7592158.html

    Problem:给定一张n个点m条边的带权有向图,从起点s出发到达终点e,有多少种方法可以走最短的路径到达终点e?

    Solution:

    首先我们得找到s到各点的单源最短路值(SPFA/Dijkstra)。

    问题一,如何确定某个点k是否在s到v的最短路上。这只需要一个判断语句:dist[s][k]+dist[k][v]==dist[s][v]。

    问题二,如何从v点出发走最短路径走到点s?找边集(v,k)使得dist[s][k]+edge[k][v]==dist[s][v]。到达点k后,我们再沿k到s的最短路走即可。为什么不是dist[s][k]+dist[k][v]==dist[s][v]?因为若是dist[k][v],k到v的最短路径上可能并非单边,而是多条边和多个点。

    知道这些后,我们可以使用搜索遍历每条s到v的最短路(从v出发),然后统计路径的条数加起来。然而这个路径数可能很大,这样子的话就会超时。

    那么我们不妨使用记忆化搜索。这样的话这个问题转换成了一个dp方程。
    状态:f[i][j] 从i到j的最短路条数值
    转移:f[i][j]=sum{f[i][k]} ( (k,j)属于E , d[i][k]+e[k][j]==d[i][j] )
    边界:f[i][i]=1

    问题得到解决。

    然而这玩意会不会有更好的解决方法?到底究竟要不要使用递归?有,可以不用递归。

    当我们跑了一边SPFA之后,以s为源,整张图会转换成一个最短路图。点u能向点v连一条有向边的条件为dist[u]+e[u][v]==dist[v]。整张图应该转成了一张DAG(边权为正)。

    那么s到一个点k的最短路,也就是f[k],应该从sum{f[j]} ( (j,k)属于E )转换过来,也就是每个出边指向k的点的路径数之和。而若想求得k,每个j都应该求得。

    是不是感觉很熟悉?想要求得一个点的信息,必须将所有指向它的点的信息全部求得。这让我们想起了拓扑排序。我们可以使用拓扑排序的顺序对每个点进行处理,由此可以使用非递归求得s到每个点的路径数。

    一开始,入度为0的点,也就是点s,显然其f[s]=1.

    本质还是dp的过程。

  • 相关阅读:
    推荐文章:深入浅出REST
    推荐Fowler作序的新书《xUnit Test Patterns》
    测试替身:Test Double
    踢毽也能治胃病,适当的运动带来健康,健康带来快乐
    10分钟入门AOP:用PostSharp普及一下AOP
    推荐一本新的英文版算法书和一本讲debug的书
    emacs开发rails的演示
    转:一个土木工程师在四川地震灾后的思考
    多语言多范型编程PPP
    巧用editplus学习正则表达式
  • 原文地址:https://www.cnblogs.com/Ning-Mew/p/7595598.html
Copyright © 2011-2022 走看看