Dijestra 最短路的java实现


问题描述:

题目描述:
已知一个无向图G=(V,E),G 中任意两个顶点 u 、v 之间存在路径或者不存在路径,如果存在,则会有一个或者多个最短路径。给出两个顶点 u0 和v0,请用一种效率尽可能高的算法求u0和v0之间的所有的最短路径。
 
输入:
第1 行:图的顶点数 1<=N<10 和边数 1<=M<=N*(N-1)/2 ,第 2...M+1行:图中的边(u,v ,w),其中 u 为边起点,v 为边终点,w 为边的权值(u 、v 、w 均为整数,1<=u<=N ,1<=v<=N ,1<=w<=100 ),第 M+2 行:u0和v0。
 
输出:
如果u0 和v0 之间没有路径,输出 0 ;其它情况:第 1 行为最短路径的条数 S 和最短路径的长度D,第 2...S+1 行中的每一行为最短路径的顶点序列 T_i(1<=i<=S) ,其中,T_1 、T_2、... 、T_S 的顺序要满足 T_i 的反向序列的字典序小于T_i+1 的反向序列的字典序的条件。例如,样例中T_1=<2,4>的反向序列为<4,2>,T_2=<2,3 ,4>的反向序列为<4,3 ,2>,则有<4,2>的字典序小于<4,3 ,2>的字典序。
 

输入示例:

输入示例:
5 8
2 1 2
1 5 2
2 3 5
2 4 6
2 5 5
3 4 1
3 5 1
4 5 2
2 4

 

输出示例:

4 6
2 4
2 3 4
2 1 5 3 4
2 1 5 4

 

下面是代码实现,方法为Dijestra标号发,复杂度为O(n^3),代码随便写写,还没整理:

 

import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Scanner;

public class MainTry2 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Net net;

		Scanner scanner = new Scanner(System.in);
		scanner.useDelimiter(System.getProperty("line.separator"));
		String temps = scanner.next();

		String[] headline = temps.split(" ");
		int nodesCount = Integer.parseInt(headline[0]);
		int edgeCount = Integer.parseInt(headline[1]);
		net = new Net(nodesCount, edgeCount);
		try {
			for (int i = 0; i < edgeCount; i++) {
				parseline(net, scanner.next());
			}
			String[] tailLine = scanner.next().split(" ");
			int beginNode = Integer.parseInt(tailLine[0]);
			int endNode = Integer.parseInt(tailLine[1]);
			net.beginNodeid = beginNode;
			net.endNodeid = endNode;
			// System.out.println("\r\n ndoescoutn:" + net.nodesCount
			// + "  edgeCoutn" + net.edgeCount + "   beinNode"
			// + net.beginNodeid + "  endNode" + net.endNodeid);
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		net.DijestraTagging();
//		System.out.println("hello over");

	}

	private static void parseline(Net net, String line) {
		Scanner linescanner = new Scanner(line);
		linescanner.useDelimiter(" ");
		int t1 = linescanner.nextInt();
		int t2 = linescanner.nextInt();
		int t3 = linescanner.nextInt();
		// System.out.println(t1 + "  " + t2+"  "+t3);
		net.initEdge(t1, t2, t3);
	}

}

class Net {
	int MAXPOACH;
	int nodesCount;
	int edgeCount;
	int[][] netEdges;
	int[][] flagAndEdge;
	int beginNodeid;
	int endNodeid;
	Node[] nodes;
	HashSet<Node> netNodeSet = new HashSet<Node>();
	String[] reversePaths;
	static int currentnthPath;

	Net(int nodeCount, int edgeCount) {
//		MAXPOACH=nodeCount^nodeCount;
		this.nodesCount = nodeCount;
		this.edgeCount = edgeCount;
		netEdges = new int[nodeCount + 1][nodeCount + 1];
		flagAndEdge = new int[4][nodeCount + 1]; // [2] 前节点 [3] 是否有多个前节点
		nodes = new Node[nodeCount + 1];
		for (int i = 1; i < nodeCount + 1; i++) {
			nodes[i] = new Node(i);
		}
		reversePaths = new String[nodesCount * nodesCount];
	}

	public void initEdge(int edgeNodeid1, int edgeNodeid2, int edgeWeight) {
		netEdges[edgeNodeid1][edgeNodeid2] = edgeWeight;
		netEdges[edgeNodeid2][edgeNodeid1] = edgeWeight;
	}

	public void printNetEdgeForDebugging() {
		for (int i = 0; i < nodesCount; i++) {
			for (int j = 0; j < nodesCount; j++) {
				System.out.print(" " + netEdges[i][j] + " ");
			}
			System.out.println("");
		}
	}

	public void putbeginNodeid(int beginNodeid) {
		this.beginNodeid = beginNodeid;
	}

	public void putendNodeid(int endNodeid) {
		this.endNodeid = endNodeid;
	}

	public void DijestraTagging() {
		flagAndEdge[0][beginNodeid] = 1;
		flagAndEdge[1][beginNodeid] = 0;

		int tempMinLength = 10000;
		int tempMinNode = 0;
		int tempEx = 0;
		int tempLengthEx = 0;

		int maxPoach = nodesCount * nodesCount;
		int k = 0;
		while ((flagAndEdge[0][endNodeid] != 1) && (k <= maxPoach)) {
			tempMinLength = 100000;
			for (int i = 1; i <= nodesCount; i++) {// 下面这个for每次只标一个点
				if (flagAndEdge[0][i] == 1) // 从表好了的结点找未标号的
				{
					tempEx = i;
					tempLengthEx = flagAndEdge[1][i];
					for (int j = 1; j <= nodesCount; j++) {
						if (netEdges[i][j] > 0 && flagAndEdge[0][j] == 0) {
							if (tempLengthEx + netEdges[i][j] < tempMinLength) {
								tempMinLength = tempLengthEx + netEdges[i][j];
								tempMinNode = j;
								tempEx = i;
							}
						}
					}
				}
			}
			// 上面已经找出待标号的点了,下面只要求从哪些点可以以最短路径连接到该点 遍历netEdges[] flagAnddge
			// 这样就可以存一个路径链接过来的 多个节点了
			for (int j = 1; j <= nodesCount; j++) {
				if (flagAndEdge[0][j] == 1 && netEdges[tempMinNode][j] > 0) {
					if (netEdges[tempMinNode][j] + flagAndEdge[1][j] == tempMinLength
							&& j != tempMinNode) {
						nodes[tempMinNode].linkedExNodes.add(j);
					}
				}
			}
			flagAndEdge[0][tempMinNode] = 1;
			flagAndEdge[1][tempMinNode] = tempMinLength;
			flagAndEdge[2][tempMinNode] = tempEx;
			flagAndEdge[3][tempMinNode]++;

			if (nodes[tempMinNode].linkedExNodes.size() > 1) {
				flagAndEdge[3][tempMinNode] = 1;// flagAndEdge[3][j]==1
												// 表示有多个前节点
			}
			k++;
		}
		if (k > maxPoach) {
			System.out.println("不存在从起始结点到终点的通路!");
			return;
		} else {
			traceBack();
		}

	}

	// String[] reversePaths = new String[nodesCount * nodesCount];

	private void addOnepath(String path) {
		
		int currentPathsCount = currentnthPath;
//		System.out.println(" currentnthPath" + currentnthPath);
//		System.out.println("path " + path);
		reversePaths[currentnthPath] = path;
		currentnthPath++;
		// reversePaths[currentPathsCount] =new String(path);
	}

	private void traceFromOneNode(int i, String prepath) {
		// if (i == beginNodeid && currentnthPath < 50) {
		if (i == beginNodeid) {
			addOnepath(prepath + i);
		} else {
			LinkedList<Integer> templl = (LinkedList<Integer>) nodes[i].linkedExNodes.clone();
			while(templl.size()>0){
				int tempint=templl.getFirst();
				traceFromOneNode(tempint, prepath+i+" ");
				templl.pop();
			}
		}
	}
private String reverseAString(String oriStr){
	StringBuffer sb=new StringBuffer();
	for(int i=oriStr.length()-1;i>=0;i--){
		sb.append(oriStr.charAt(i));
	}
	return sb.toString();
}
public void traceExNodes(){
	for(int i=0;i<nodes.length;i++){
		Node node=nodes[i];
		Iterator it=node.linkedExNodes.iterator();
		System.out.print("Exnodes of node"+i+": ");
		while(it.hasNext()){
			Integer in=(Integer) it.next();
			System.out.print("\t "+in);
		}
		System.out.println(" ");
	}
}


	public void traceBack() {
		// 深度优先 反向追踪 得到最短路径 ,以字符串形式表示,排序后, 然后 逆着输出字符串
//		System.out.println("here to traceBack");
		traceFromOneNode(endNodeid, "");
		
		System.out.println(currentnthPath+" "+flagAndEdge[1][endNodeid]);
//		下面正着输出 路径
		String[] orderPaths=new String[currentnthPath];
		for(int i=0;i<currentnthPath;i++){
			orderPaths[i]=reversePaths[i];
		}
		Arrays.sort(orderPaths);
		for(int i=0;i<currentnthPath;i++){
			System.out.println(reverseAString(reversePaths[i]));
		}

		
//		System.out.println("Shortest len:" + flagAndEdge[1][endNodeid]);
		for (int i = 1; i <= nodesCount; i++) {
			Iterator it = nodes[i].linkedExNodes.iterator();
//			System.out.println("exNode" + i + ":  ");
			while (it.hasNext()) {
				Integer n = (Integer) it.next();
//				System.out.print(n);
			}
//			System.out.println("\r\n");
		}
	}

	public void printPaths() {

	}
}

class Node {
	public String exNodesCount;
	int nodeid;
	int lenToBeginNode;
	int[] preNodes;
	LinkedList<Integer> linkedExNodes = new LinkedList<Integer>();

	// int exNodesCount = linkedExNodes.size();

	public int getexNodesCount() {
		// System.out.println("here come to size"+exNodesCount);
		return linkedExNodes.size();
		// linkedExNodes.a
	}

	public Node(int nodeid) {
		this.nodeid = nodeid;
	}

	public int getNodeid() {
		return this.nodeid;
	}

	public int getLenToBeginNode() {
		return this.lenToBeginNode;
	}

	public LinkedList getlinkedExNodes() {
		return this.getlinkedExNodes();
	}
}


下面是两个测试用例的数据:

测试数据一:

5 6
1 2 1
1 3 3
2 3 2
2 4 1
3 4 1
3 5 1
1 5

测试数据二:

5 8
2 1 2
1 5 2
2 3 5
2 4 6
2 5 5
3 4 1
3 5 1
4 5 2
2 4

 

注意使用Scanner的话最后一行的enter不能忘了哦……测试时把scannenr参数该为文件吧

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值