/*寻找有负环加权有向图的最短路径,如果顶点能到达负环就不存在最短路径,这是问题转换成找负环
如果顶点不能到达负环就找能到达点的最短路径。
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)