您的位置:首页 > 编程语言 > Java开发

算法导论——24.2 DAG最短路径算法java实现

2017-05-08 23:43 549 查看

介绍

Bellman-Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题,但是对于DAG,可以有更加简化的算法去计算,使得时间复杂度更低。

针对DAG的特点,以拓扑排序为基础,提出了解决DAG的最短路径问题的简单算法。通过理论分析,表明该算法具有理想的运算效率,其中,解决单源点问题的运算时间与E成正比,解决所有点对问题的运算时间与VE成正比。拓扑排序策略对于此类最短路径问题的研究,较传统的方法运算简单、求解直观。

适用条件&范围

1.单源最短路径(从源点s到其它所有顶点v);
2.有向无环图(DAG)

3.边权可正可负;

算法描述

(1)初始化,入度为0的节点d为0,其他的节点d值为INF。

(2)对DAG进行拓扑排序,得到拓扑序列。

(3)按照拓扑序列遍历DAG的点,进行松弛操作,对于每个点u,遍历其所有的出边<u,v>,如果d[v] > d[v] + length<u,v>,则更新。

时间复杂度

算法时间复杂度O(V+E)。

Java代码实现



package algorithms;

import util.AlgoGraph;

/**
* Created with IntelliJ IDEA.
* Created by The_Sam on 2017/5/8 22:08
*/
public class DAG extends ShortestAlgorithms {
public static void main(String[] args) {
ShortestAlgorithms dag = new DAG();
System.out.println(dag.analyse(AlgoGraph.defaultMap3()));
}

boolean analyse(AlgoGraph algoGraph) {
dis = new int[algoGraph.getNodenum()];//dis[i] 为 i点到s的最短距离
pre = new int[algoGraph.getNodenum()];//pre[i] 为i搭配s的最短距离的上一个节点
ini(algoGraph, algoGraph.getNodenum());
int vertexs[] = topSort(algoGraph);
relex(algoGraph, algoGraph.getNodenum(), algoGraph.getEdgenum(), vertexs);
return true;
}

void ini(AlgoGraph algoGraph, int nodenum) {
//初始化,将dis[s]设为0,其他的都设为无限大
int s = algoGraph.getOriginal();//原点
for (int i = 0; i < nodenum; i++) {
dis[i] = i == s ? 0 : MAXN;
}
}

void relex(AlgoGraph algoGraph, int nodenum, int edgenum, int vertexs[]) {
//松弛操作,遍历每条边nodenum次,找到所有节点的对应dis和pre
// 实际上就是暴力检测有没有更短的路径
for (int i = 0; i < nodenum; i++) {
for (int j = 0; j < edgenum; j++) {
int v = algoGraph.edge.get(j).v;
if (v != vertexs[i]) continue;//对拓扑排序从前往后操作,省去后面很多多余的操作
int u = algoGraph.edge.get(j).u;
int cost = algoGraph.edge.get(j).cost;
if (dis[v] > dis[u] + cost) {
dis[v] = dis[u] + cost;
pre[v] = u;
}
}
}
}

/**
* @Description : 拓扑排序
* @Author : The_Sam
* @Datetime : 2017/5/8 23:22
* @Params : AlgoGraph algoGraph
* @Return : int[]
*/
int[] topSort(AlgoGraph algoGraph) {
int nodeNum = algoGraph.getNodenum();
int result[] = new int[nodeNum];
int indegrees[] = algoGraph.getIndegrees();
for (int cnt = 0; cnt < nodeNum; ) {
for (int i = 0; i < nodeNum; i++) {
if (indegrees[i] == 0) result[cnt++] = i;
if (indegrees[i] >= 0) indegrees[i]--;
}
}
return result;
}

}

AlgoGraph.java 表示图的代码附上
package util;

import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;

/**
* Created by The_Sam on 2017/5/8.
* 图是从0到nodenum-1表示相应节点
*/
public class AlgoGraph {
@Getter
@Setter
private int original;
@Getter
@Setter
private int nodenum;
private int indegrees[];
//    private int indegrees[];//indegree[i]表示i节点的入度
public ArrayList<AlgoEdge> edge;

public int getEdgenum() {
return edge.size();
}

public AlgoGraph(int original, int nodenum, ArrayList<AlgoEdge> edge) {
this.original = original;
this.nodenum = nodenum;
this.edge = edge;
}

/**
* @Description :返回函数各个节点的入度
* @Author : The_Sam
* @Datetime : 2017/5/8 23:04
* @Params :
* @Return : int[]
*/
public int[] getIndegrees() {
indegrees=new int[nodenum];
for (AlgoEdge e :
edge) {
indegrees[e.v]++;
}
return indegrees;
}

/**
* @Description: 返回一个图,为算法导论图24-4,带负权无负权回路有向环图
* @Author: The_Sam
* @Datetime: 2017/5/8 21:22
* @Params: []
* @Return: AlgoGraph
*/
static public AlgoGraph defaultMap1() {
ArrayList<AlgoEdge> edge = new ArrayList<AlgoEdge>();
edge.add(new AlgoEdge(0, 1, 6));
edge.add(new AlgoEdge(0, 2, 7));
edge.add(new AlgoEdge(1, 2, 8));
edge.add(new AlgoEdge(1, 3, 5));
edge.add(new AlgoEdge(1, 4, -4));
edge.add(new AlgoEdge(2, 3, -3));
edge.add(new AlgoEdge(2, 4, 9));
edge.add(new AlgoEdge(3, 1, -2));
edge.add(new AlgoEdge(4, 0, 2));
edge.add(new AlgoEdge(4, 3, 7));
int original = 0;
int nodenum = 5;
return new AlgoGraph(original, nodenum, edge);
}

/**
* @Description: 返回一个图,为算法导论图24-4改变版,有负权回路有向环图
* @Author: The_Sam
* @Datetime: 2017/5/8 21:22
* @Params: []
* @Return: AlgoGraph
*/
static public AlgoGraph defaultMap2() {
ArrayList<AlgoEdge> edge = new ArrayList<AlgoEdge>();
edge.add(new AlgoEdge(0, 1, 6));
edge.add(new AlgoEdge(0, 2, 7));
edge.add(new AlgoEdge(1, 2, 8));
edge.add(new AlgoEdge(1, 3, 5));
edge.add(new AlgoEdge(1, 4, -4));
edge.add(new AlgoEdge(2, 3, -3));
edge.add(new AlgoEdge(2, 4, 9));
edge.add(new AlgoEdge(3, 1, -2));
edge.add(new AlgoEdge(4, 0, 2));
edge.add(new AlgoEdge(4, 3, 5));//此处改变 edge.add(new AlgoEdge(4, 3, 7));
int original = 0;
int nodenum = 5;
return new AlgoGraph(original, nodenum, edge);
}
/**
* @Description: 返回一个图,为算法导论图24-4改变版,有向无环图
* @Author: The_Sam
* @Datetime: 2017/5/8 21:22
* @Params: []
* @Return: AlgoGraph
*/
static public AlgoGraph defaultMap3() {
ArrayList<AlgoEdge> edge = new ArrayList<AlgoEdge>();
edge.add(new AlgoEdge(0, 1, 6));
edge.add(new AlgoEdge(0, 2, 7));
edge.add(new AlgoEdge(1, 2, 8));
edge.add(new AlgoEdge(1, 3, 5));
edge.add(new AlgoEdge(1, 4, -4));
edge.add(new AlgoEdge(2, 3, -3));
edge.add(new AlgoEdge(2, 4, 9));
//edge.add(new AlgoEdge(3, 1, -2));
//edge.add(new AlgoEdge(4, 0, 2));
//edge.add(new AlgoEdge(4, 3, 5));//此处改变 edge.add(new AlgoEdge(4, 3, 7));
int original = 0;
int nodenum = 5;
return new AlgoGraph(original, nodenum, edge);
}
/**
* @Description: 返回一个图,为算法导论图24-4改变版,无负权有向环图
* @Author: The_Sam
* @Datetime: 2017/5/8 21:22
* @Params: []
* @Return: AlgoGraph
*/
static public AlgoGraph defaultMap4() {
ArrayList<AlgoEdge> edge = new ArrayList<AlgoEdge>();
edge.add(new AlgoEdge(0, 1, 6));
edge.add(new AlgoEdge(0, 2, 7));
edge.add(new AlgoEdge(1, 2, 8));
edge.add(new AlgoEdge(1, 3, 5));
edge.add(new AlgoEdge(1, 4, 4));
edge.add(new AlgoEdge(2, 3, 3));
edge.add(new AlgoEdge(2, 4, 9));
//edge.add(new AlgoEdge(3, 1, -2));
//edge.add(new AlgoEdge(4, 0, 2));
//edge.add(new AlgoEdge(4, 3, 5));//此处改变 edge.add(new AlgoEdge(4, 3, 7));
int original = 0;
int nodenum = 5;
return new AlgoGraph(original, nodenum, edge);
}
}

AlgoEdge.java表示边的代码附上
package util;

/**
* Created by The_Sam on 2017/5/8.
*/
public class AlgoEdge {
public int u,v;
public int cost;

public AlgoEdge(int u, int v, int cost) {
this.u = u;
this.v = v;
this.cost = cost;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法 DAG