配色: 字号:
Johnson 全源最短路径算法
2016-09-07 | 阅:  转:  |  分享 
  
Johnson全源最短路径算法

解决单源最短路径问题(SingleSourceShortestPathsProblem)的算法包括:



Dijkstra单源最短路径算法:时间复杂度为O(E+VlogV),要求权值非负;

Bellman-Ford单源最短路径算法:时间复杂度为O(VE),适用于带负权值情况;

对于全源最短路径问题(All-PairsShortestPathsProblem),可以认为是单源最短路径问题的推广,即分别以每个顶点作为源顶点并求其至其它顶点的最短距离。例如,对每个顶点应用Bellman-Ford算法,则可得到所有顶点间的最短路径的运行时间为O(V2E),由于图中顶点都是连通的,而边的数量可能会比顶点更多,这个时间没有比Floyd-Warshall全源最短路径算法O(V3)更优。那么,再试下对每个顶点应用Dijkstra算法,则可得到所有顶点间的最短路径的运行时间为O(VE+V2logV),看起来优于Floyd-Warshall算法的O(V3),所以看起来使用基于Dijkstra算法的改进方案好像更好,但问题是Dijkstra算法要求图中所有边的权值非负,不适合通用的情况。



在1977年,DonaldB.Johnson提出了对所有边的权值进行"re-weight"的算法,使得边的权值非负,进而可以使用Dijkstra算法进行最短路径的计算。



我们先自己思考下如何进行"re-weight"操作,比如,简单地对每条边的权值加上一个较大的正数,使其非负,是否可行?



111

s-----a-----b-----c

\/

\/

\______/

4

比如上面的图中,共4条边,权值分别为1,1,1,4。当前s-->c的最短路径是{s-a,a-b,b-c}即1+1+1=3。而如果将所有边的权值加1,则最短路径就会变成{s-c}的5,因为2+2+2=6,实际上导致了最短路径的变化,显然是错误的。



那么,Johnson算法是如何对边的权值进行"re-weight"的呢?以下面的图G为例,有4个顶点和5条边。







首先,新增一个源顶点4,并使其与所有顶点连通,新边赋权值为0,如下图所示。







使用Bellman-Ford算法计算新的顶点到所有其它顶点的最短路径,则从4至{0,1,2,3}的最短路径分别是{0,-5,-1,0}。即有h[]={0,-5,-1,0}。当得到这个h[]信息后,将新增的顶点4移除,然后使用如下公式对所有边的权值进行"re-weight":



w(u,v)=w(u,v)+(h[u]-h[v]).

则可得到下图中的结果:







此时,所有边的权值已经被"re-weight"为非负。此时,就可以利用Dijkstra算法对每个顶点分别进行最短路径的计算了。



Johnson算法描述如下:



给定图G=(V,E),增加一个新的顶点s,使s指向图G中的所有顶点都建立连接,设新的图为G’;

对图G’中顶点s使用Bellman-Ford算法计算单源最短路径,得到结果h[]={h[0],h[1],..h[V-1]};

对原图G中的所有边进行"re-weight",即对于每个边(u,v),其新的权值为w(u,v)+(h[u]-h[v]);

移除新增的顶点s,对每个顶点运行Dijkstra算法求得最短路径;

Johnson算法的运行时间为O(V2logV+VE)。



Johnson算法伪码实现如下:







Johnson算法C#代码实现如下:



复制代码

1usingSystem;

2usingSystem.Collections.Generic;

3usingSystem.Linq;

4

5namespaceGraphAlgorithmTesting

6{

7classProgram

8{

9staticvoidMain(string[]args)

10{

11//buildadirectedandnegativeweightedgraph

12GraphdirectedGraph1=newGraph(5);

13directedGraph1.AddEdge(0,1,-1);

14directedGraph1.AddEdge(0,2,4);

15directedGraph1.AddEdge(1,2,3);

16directedGraph1.AddEdge(1,3,2);

17directedGraph1.AddEdge(1,4,2);

18directedGraph1.AddEdge(3,2,5);

19directedGraph1.AddEdge(3,1,1);

20directedGraph1.AddEdge(4,3,-3);

21

22Console.WriteLine();

23Console.WriteLine("GraphVertexCount:{0}",directedGraph1.VertexCount);

24Console.WriteLine("GraphEdgeCount:{0}",directedGraph1.EdgeCount);

25Console.WriteLine();

26

27int[,]distSet1=directedGraph1.Johnsons();

28PrintSolution(directedGraph1,distSet1);

29

30//buildadirectedandpositiveweightedgraph

31GraphdirectedGraph2=newGraph(4);

32directedGraph2.AddEdge(0,1,5);

33directedGraph2.AddEdge(0,3,10);

34directedGraph2.AddEdge(1,2,3);

35directedGraph2.AddEdge(2,3,1);

36

37Console.WriteLine();

38Console.WriteLine("GraphVertexCount:{0}",directedGraph2.VertexCount);

39Console.WriteLine("GraphEdgeCount:{0}",directedGraph2.EdgeCount);

40Console.WriteLine();

41

42int[,]distSet2=directedGraph2.Johnsons();

43PrintSolution(directedGraph2,distSet2);

44

45Console.ReadKey();

46}

47

48privatestaticvoidPrintSolution(Graphg,int[,]distSet)

49{

50Console.Write("\t");

51for(inti=0;i
52{

53Console.Write(i+"\t");

54}

55Console.WriteLine();

56Console.Write("\t");

57for(inti=0;i
58{

59Console.Write("-"+"\t");

60}

61Console.WriteLine();

62for(inti=0;i
63{

64Console.Write(i+"|\t");

65for(intj=0;j
66{

67if(distSet[i,j]==int.MaxValue)

68{

69Console.Write("INF"+"\t");

70}

71else

72{

73Console.Write(distSet[i,j]+"\t");

74}

75}

76Console.WriteLine();

77}

78}

79

80classEdge

81{

82publicEdge(intbegin,intend,intweight)

83{

84this.Begin=begin;

85this.End=end;

86this.Weight=weight;

87}

88

89publicintBegin{get;privateset;}

90publicintEnd{get;privateset;}

91publicintWeight{get;privateset;}

92

93publicvoidReweight(intnewWeight)

94{

95this.Weight=newWeight;

96}

97

98publicoverridestringToString()

99{

100returnstring.Format(

101"Begin[{0}],End[{1}],Weight[{2}]",

102Begin,End,Weight);

103}

104}

105

106classGraph

107{

108privateDictionary>_adjacentEdges

109=newDictionary>();

110

111publicGraph(intvertexCount)

112{

113this.VertexCount=vertexCount;

114}

115

116publicintVertexCount{get;privateset;}

117

118publicintEdgeCount

119{

120get

121{

122return_adjacentEdges.Values.SelectMany(e=>e).Count();

123}

124}

125

126publicvoidAddEdge(intbegin,intend,intweight)

127{

128if(!_adjacentEdges.ContainsKey(begin))

129{

130varedges=newList();

131_adjacentEdges.Add(begin,edges);

132}

133

134_adjacentEdges[begin].Add(newEdge(begin,end,weight));

135}

136

137publicvoidAddEdge(Edgeedge)

138{

139AddEdge(edge.Begin,edge.End,edge.Weight);

140}

141

142publicvoidAddEdges(IEnumerableedges)

143{

144foreach(varedgeinedges)

145{

146AddEdge(edge);

147}

148}

149

150publicIEnumerableGetAllEdges()

151{

152return_adjacentEdges.Values.SelectMany(e=>e);

153}

154

155publicint[,]Johnsons()

156{

157//distSet[,]willbetheoutputmatrixthatwillfinallyhavetheshortest

158//distancesbetweeneverypairofvertices

159int[,]distSet=newint[VertexCount,VertexCount];

160

161for(inti=0;i
162{

163for(intj=0;j
164{

165distSet[i,j]=int.MaxValue;

166}

167}

168for(inti=0;i
169{

170distSet[i,i]=0;

171}

172

173//step1:addnewvertexsandconnecttoallvertices

174Graphg=newGraph(this.VertexCount+1);

175g.AddEdges(this.GetAllEdges());

176

177ints=this.VertexCount;

178for(inti=0;i
179{

180g.AddEdge(s,i,0);

181}

182

183//step2:useBellman-Fordtoevaluateshortestpathsfroms

184int[]h=g.BellmanFord(s);

185

186//step3:re-weightingedgesoftheoriginalgraph

187//w(u,v)=w(u,v)+(h[u]-h[v])

188foreach(varedgeinthis.GetAllEdges())

189{

190edge.Reweight(edge.Weight+(h[edge.Begin]-h[edge.End]));

191}

192

193//step4:useDijkstraforeachedges

194for(intbegin=0;begin
195{

196int[]dist=this.Dijkstra(begin);

197for(intend=0;end
198{

199if(dist[end]!=int.MaxValue)

200{

201distSet[begin,end]=dist[end]-(h[begin]-h[end]);

202}

203}

204}

205

206returndistSet;

207}

208

209publicint[,]FloydWarshell()

210{

211/distSet[,]willbetheoutputmatrixthatwillfinallyhavetheshortest

212distancesbetweeneverypairofvertices/

213int[,]distSet=newint[VertexCount,VertexCount];

214

215for(inti=0;i
216{

217for(intj=0;j
218{

219distSet[i,j]=int.MaxValue;

220}

221}

222for(inti=0;i
223{

224distSet[i,i]=0;

225}

226

227/Initializethesolutionmatrixsameasinputgraphmatrix.Or

228wecansaytheinitialvaluesofshortestdistancesarebased

229onshortestpathsconsideringnointermediatevertex./

230foreach(varedgein_adjacentEdges.Values.SelectMany(e=>e))

231{

232distSet[edge.Begin,edge.End]=edge.Weight;

233}

234

235/Addallverticesonebyonetothesetofintermediatevertices.

236--->Beforestartofaiteration,wehaveshortestdistancesbetweenall

237pairsofverticessuchthattheshortestdistancesconsideronlythe

238verticesinset{0,1,2,..k-1}asintermediatevertices.

239--->Aftertheendofaiteration,vertexno.kisaddedtothesetof

240intermediateverticesandthesetbecomes{0,1,2,..k}/

241for(intk=0;k
242{

243//Pickallverticesassourceonebyone

244for(inti=0;i
245{

246//Pickallverticesasdestinationfortheabovepickedsource

247for(intj=0;j
248{

249//Ifvertexkisontheshortestpathfrom

250//itoj,thenupdatethevalueofdistSet[i,j]

251if(distSet[i,k]!=int.MaxValue

252&&distSet[k,j]!=int.MaxValue

253&&distSet[i,k]+distSet[k,j]
254{

255distSet[i,j]=distSet[i,k]+distSet[k,j];

256}

257}

258}

259}

260

261returndistSet;

262}

263

264publicint[]BellmanFord(intsource)

265{

266//distSet[i]willholdtheshortestdistancefromsourcetoi

267int[]distSet=newint[VertexCount];

268

269//Step1:InitializedistancesfromsourcetoallotherverticesasINFINITE

270for(inti=0;i
271{

272distSet[i]=int.MaxValue;

273}

274distSet[source]=0;

275

276//Step2:Relaxalledges|V|-1times.Asimpleshortestpathfromsource

277//toanyothervertexcanhaveat-most|V|-1edges

278for(inti=1;i<=VertexCount-1;i++)

279{

280foreach(varedgein_adjacentEdges.Values.SelectMany(e=>e))

281{

282intu=edge.Begin;

283intv=edge.End;

284intweight=edge.Weight;

285

286if(distSet[u]!=int.MaxValue

287&&distSet[u]+weight
288{

289distSet[v]=distSet[u]+weight;

290}

291}

292}

293

294//Step3:checkfornegative-weightcycles.Theabovestepguarantees

295//shortestdistancesifgraphdoesn''tcontainnegativeweightcycle.

296//Ifwegetashorterwww.wang027.compath,thenthereisacycle.

297foreach(varedgein_adjacentEdges.Values.SelectMany(e=>e))

298{

299intu=edge.Begin;

300intv=edge.End;

301intweight=edge.Weight;

302

303if(distSet[u]!=int.MaxValue

304&&distSet[u]+weight
305{

306Console.WriteLine("Graphcontainsnegativeweightcycle.");

307}

308}

309

310returndistSet;

311}

312

313publicint[]Dijkstra(intsource)

314{

315//dist[i]willholdtheshortestdistancefromsourcetoi

316int[]distSet=newint[VertexCount];

317

318//sptSet[i]willtrueifvertexiisincludedinshortest

319//pathtreeorshortestdistancefromsourcetoiisfinalized

320bool[]sptSet=newbool[VertexCount];

321

322//initializealldistancesasINFINITEandstpSet[]asfalse

323for(inti=0;i
324{

325distSet[i]=int.MaxValue;

326sptSet[i]=false;

327}

328

329//distanceofsourcevertexfromitselfisalways0

330distSet[source]=0;

331

332//findshortestpathforallvertices

333for(inti=0;i
334{

335//picktheminimumdistancevertexfromthesetofverticesnot

336//yetprocessed.uisalwaysequaltosourceinfirstiteration.

337intu=CalculateMinDistance(distSet,sptSet);

338

339//markthepickedvertexasprocessed

340sptSet[u]=true;

341

342//updatedistvalueoftheadjacentverticesofthepickedvertex.

343for(intv=0;v
344{

345//updatedist[v]onlyifisnotinsptSet,thereisanedgefrom

346//utov,andtotalweightofpathfromsourcetovthroughuis

347//smallerthancurrentvalueofdist[v]

348if(!sptSet[v]

349&&distSet[u]!=int.MaxValue

350&&_adjacentEdges.ContainsKey(u)

351&&_adjacentEdges[u].Exists(e=>e.End==v))

352{

353intd=_adjacentEdges[u].Single(e=>e.End==v).Weight;

354if(distSet[u]+d
355{

356distSet[v]=distSet[u]+d;

357}

358}

359}

360}

361

362returndistSet;

363}

364

365privateintCalculateMinDistance(int[]distSet,bool[]sptSet)

366{

367intminDistance=int.MaxValue;

368intminDistanceIndex=-1;

369

370for(intv=0;v
371{

372if(!sptSet[v]&&distSet[v]<=minDistance)

373{

374minDistance=distSet[v];

375minDistanceIndex=v;

376}

377}

378

379returnminDistanceIndex;

380}

381}

382}

383}

献花(0)
+1
(本文系thedust79首藏)