js版本有负环加权有向图的最短路径bellman-ford算法

/*寻找有负环加权有向图的最短路径,如果顶点能到达负环就不存在最短路径,这是问题转换成找负环
如果顶点不能到达负环就找能到达点的最短路径。
bellmanFordSP的relax(pq.shift(),G)不能换成relax(pq.pop(),G),否则会变成深度优先搜索,要relax的点可能变多,
例如G={0:[[1,0.5],[2,0.5]],1:[[3,0.5]],2:[[3,-0.5]],******}(这里为了方便查看用对象表示),
如果先走0->1->3,那么所有点被relax后再被走0->2->3的路径全部relax一次,
用shift的话0->1->3的路径变成0->2->3,这样其他点可以少relax一次。
最坏的情况:
每轮relax的下一轮即可能多的继续relax,比如G={0:[1,2,**,V-1],1:[2,**,V-1],2:[3,**,V-1],****},
小点到大点距离为正,大点到小点距离为负,但和为正。设置合适的权重,使得0->2->1的权重小于0->1,
0->3->2的权重小于0->2,以此类推。时间复杂度确实和EV成正比。
*/

function bellmanFordSP(start,G){
    pq.push(start)
    var c=0
    while(pq.length>0&!hasCycle){
        relax(pq.shift(),G)
        //relax(pq.pop(),G)     			 
        if(++c%V==0){
            findNegativeCycle(G)
        }
    }
}

function relax(v,G){
    onpq[v]=false
    for(let i in G[v]){
        let e=G[v][i]
        let w=e[0],d=e[1]
        if(dist[w]>dist[v]+d){
            dist[w]=dist[v]+d
            from[w]=v
            if(!onpq[v]){
                pq.push(w)
                onpq[w]=true
            }
        }
    }
}

//检测负权重的环,书上没找到代码
function findNegativeCycle(G){
    var marked=[]
    for(let i=0;i<V;i++){
        var v=i
        var cycle=[]
        while(1){
            if(v==undefined)break
            let ind=cycle.indexOf(v)
            if(ind!=-1){
                var cycle_=cycle.splice(0,ind+1)
                cycle_.unshift(v)
                console.log('cycle-->',cycle_)
                hasCycle=true
                return
            }
            if(marked[v])break
            cycle.unshift(v)
            marked[v]=true
            v=from[v]
        }
    }
}

var hasCycle=false
let V=99
var pq=[]
var onpq=[]
var dist=[0]
let maxDist=Math.pow(2,31)-1
for(let i=1;i<V;i++){dist[i]=maxDist}
var from=[]
let generateDirectedGraph=require('./wgraph').generateDirectedGraph
let generateEdges=require('./wgraph').generateEdges
let es=generateEdges(V,V*3,9,0)
var G=generateDirectedGraph(V,es,false)
for(let i=0;i<V;i++){console.log(i+':'+G[i])}
bellmanFordSP(0,G)
console.log(dist,'\n',from)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值