动态规划求解带权有向图最短路径问题

求带权有向图的最短路径问题,最通用也是最容易想到的就是用Dijkstra算法求解,但是有一部分特定的带权有向图最短路径问题也可以用动态规划求解。

这道题看到第一眼很明显就可以生成一张图,然后用带权图的最短路径搜索来做,即Dijkstra算法,但是实际上也可以用动态规划来做,而且这种题还是非常典型的动态规划题目。

得出一个动态规划算法的要点就是想出状态转移方程,这道题的状态转移方程非常明显,建立一个二维数组,行数为i,列数为j

那么dp[i][j]=min(dp[i-1][j],dp[i][j-1])+m[i][j],用中文写大概就是 

从初始点出发到第i行第j列的最短路径为=两条路线的小值(路径1:初始点到该点左边的路径,路径2:初始点到该点上方的路径)+该点的权值

在例题数据中随便取一点3,可以看出依赖于左方的1和上方的5。

那么接下来根据数学归纳法只要先列出基本情况,然后按照依赖方向递推计算,最后就可以得到初始点1到该矩阵任意一点的最短路径,当然也包括到终点0的最短路径

基本情况就是顶点没有左顶点或者没有上顶点,那么就是第一行和第一列,将他们填充为初始值即可。

剩下的所有值都可以根据该依赖来计算,根据依赖方向,按行来算和按列来算都可以,只要保证计算一个值的依赖值都被计算过即可。


比较一下这个算法和Dijkstra算法,可以看到该算法其实求解了多余的节点,许多在最短路径中没有出现过的节点也被计算到了,如果用Dijkstra算法的话,很可能会少计算一些节点。不过只要将该动态规划变成带记忆的从顶向下算法,就可以避免这个问题。

虽然只是求最短路径的话,两种算法都可以

再看另外一个题,这道题就没法用Dijkstra算法来求了

这是一个codewar上的题

https://www.codewars.com/kata/551f23362ff852e2ab000037/java

题目简单意思就是求最长路径

Dijkstra算法是求不出最长路径的,而且任何的贪婪算法都求不出最长路径,所以此时时间复杂度最低的办法还是用动态规划。

解法如下

    public static int longestSlideDown(int[][] pyramid) {

        int[][] temp = new int[pyramid.length][];
        //为了不改变原始数据先复制一份
        for (int y = 0; y < pyramid.length; y++) {
            temp[y] = new int[pyramid[y].length];
            for (int x = 0; x < pyramid[y].length; x++) {
                temp[y][x] = pyramid[y][x];
            }
        }

        //按照依赖方向从上到下计算
        for (int y = 0; y < pyramid.length - 1; y++) {
            for (int x = 0; x < pyramid[y].length; x++) {
                //状态转移方程
                temp[y + 1][x] = Math.max(temp[y + 1][x], temp[y][x] + pyramid[y + 1][x]);
                temp[y + 1][x + 1] = Math.max(temp[y + 1][x + 1], temp[y][x] + pyramid[y + 1][x + 1]);
            }
        }
    
        return Arrays.stream(temp[temp.length - 1]).max().getAsInt();
    }

 

 


这种题型也是常见的动态规划考题,但是我们也可以从中归纳出一些东西,最后总结如下

只要一个有向图没有环,(就是他实际上是一棵树)则该图中任意两点间的最短路径就可以用以上动态规划方法来进行求解,只要搞清楚以下依赖,即从初始点到x点的最短路径等于所有进入x点的顶点的最短路径,再加上对应边的权,取其中最小值。基本情况就是没有入边的顶点。

如下是某个不带环的图的一部分,ABC是所有进入D的顶点,那么图中任意一点到D点的最短路径必然经过ABC中的一点,所以图中任意一点到D的最短路径就是任意一点到A或者B或者C的最短路径再加上ABC到D对应边的权,然后取其中最小值。

那么为什么有环就不能用常规的动态规划方法求解呢,因为会出现循环依赖,这样的话就没法进行递推计算了。不过也可以用一些方法预处理掉环再用动态规划,不过一般出现这样的情况,还是直接用一些启发式的最短路径算法时间复杂度更低

 

 

 

 

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 狄克斯特拉算法是一种用于求解带权有向图最短路径算法。其基本思想是从起点开始,逐步扩展到其他节点,每次选择当前距离起点最近的节点,并更新其周围节点的距离。通过不断迭代,最终得到起点到所有节点的最短路径。 ### 回答2: 狄克斯特拉算法(Dijkstra's Algorithm)是一种用于求解带有权重的有向图最短路径算法。该算法的基本思想是通过不断更新起点到其他顶点的最短距离,从而找到起点到终点的最短路径。 具体步骤如下: 1. 创建一个集合S,用于存放已经找到最短路径的顶点,以及一个数组dist,用于存放起点到各个顶点的最短距离。初始时集合S为空,起点到其他顶点的距离为无穷大。 2. 将起点加入到集合S中,并将起点到自身的距离设为0。 3. 对于起点的邻居顶点,更新其距离。即对于起点的每个邻居顶点v,如果起点经过当前顶点u到达v的距离(dist[u]+weight[u][v])小于dist[v],则更新dist[v]为(dist[u]+weight[u][v])。 4. 从未加入集合S的顶点中选择距离起点最近的顶点u,并将其加入到集合S中。 5. 重复步骤3-4,直到所有顶点都加入集合S中,或者没有可更新的距离的顶点。 6. 根据dist数组,可以找到起点到任意顶点的最短距离。 需要注意的是,狄克斯特拉算法只适用于没有负权边的图,如果图中存在负权边,可以考虑使用其他算法如贝尔曼-福特算法(Bellman-Ford Algorithm)或弗洛伊德算法(Floyd-Warshall Algorithm)来求解最短路径。 总结起来,狄克斯特拉算法是一种通过不断更新起点到各个顶点的最短距离来求解带权有向图最短路径算法。它的时间复杂度为O(V^2),其中V为顶点个数。 ### 回答3: 狄克斯特拉算法(Dijkstra's algorithm)是一种用于解决带权有向图最短路径问题算法。下面就以一个简单的例子来说明狄克斯特拉算法的具体步骤。 假设有一个带权有向图,其中包含了一些节点和边。我们要找到从起点到终点的最短路径,其中每条边都有一个权重值表示距离,路径上的权重之和就是路径的总距离。 狄克斯特拉算法的步骤如下: 1. 初始化。将起点的距离设置为0,其他节点的距离设置为无穷大。同时将起点标记为当前节点。 2. 更新距离。从起点出发,遍历所有与当前节点相邻的节点。如果通过当前节点到达这些相邻节点的距离比之前记录的距离更短,就更新这些节点的距离。重复这个步骤,直到遍历完所有节点。 3. 选择下一个节点。从尚未处理的节点中选择距离最小的节点,并标记为当前节点。 4. 重复步骤2和3,直到找到终点或者遍历完所有节点。 5. 最短路径还原。从终点开始,通过记录的距离和上一步选择的节点,依次反向找到起点,即可得到最短路径。 狄克斯特拉算法的时间复杂度是O(V^2),其中V是节点的数量。它适用于有向无环图和非负权重的情况。 总结以上就是用狄克斯特拉算法求解带权有向图最短路径的过程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值