最簡單的解決方案是按照Dijkstra算法忽略每個邊權重並計算最短路徑。
可以使用AsUnweightedDirectedGraph
類從加權有向圖創建未加權有向圖。這簡單地覆蓋了每個邊的getEdgeWeight
方法並返回1.0
,即默認權重。
Graph<String, DefaultWeightedEdge> unweightedGraph = new AsUnweightedDirectedGraph<>(graph);
List<DefaultWeightedEdge> path = DijkstraShortestPath.findPathBetween(unweightedGraph, "1", "3");
System.out.println(path); // prints [(1 : 2), (2 : 3)]
這可能不會提供最佳性能。爲了改進它,你可以建立你自己的BreadthFirstIterator
來遍歷圖表。此代碼基於this class,但更新爲與更新版本的JGraphT相匹配。它提供了一個BFSShortestPath
類,無論每個邊上的權重如何,都可以在BFS中找到兩個頂點之間的最短路徑。
public class Test {
public static void main(String[] args) {
SimpleDirectedWeightedGraph<String, DefaultWeightedEdge> graph =
new SimpleDirectedWeightedGraph<String, DefaultWeightedEdge>(DefaultWeightedEdge.class);
graph.addVertex("1");
graph.addVertex("2");
graph.addVertex("3");
graph.addVertex("4");
graph.addVertex("5");
DefaultWeightedEdge e1 = graph.addEdge("1", "2");
graph.setEdgeWeight(e1, 5);
DefaultWeightedEdge e2 = graph.addEdge("2", "3");
graph.setEdgeWeight(e2, 10);
DefaultWeightedEdge e3 = graph.addEdge("2", "4");
graph.setEdgeWeight(e3, 2);
DefaultWeightedEdge e4 = graph.addEdge("4", "5");
graph.setEdgeWeight(e4, 2);
DefaultWeightedEdge e5 = graph.addEdge("5", "3");
graph.setEdgeWeight(e5, 2);
System.out.println(BFSShortestPath.findPathBetween(graph, "1", "3"));
}
}
final class BFSShortestPath {
private BFSShortestPath() {} // ensure non-instantiability.
public static <V, E> List<E> findPathBetween(Graph<V, E> graph, V startVertex, V endVertex) {
MyBreadthFirstIterator<V, E> iter = new MyBreadthFirstIterator<>(graph, startVertex);
while (iter.hasNext()) {
Object vertex = iter.next();
if (vertex.equals(endVertex)) {
return createPath(iter, endVertex);
}
}
return null;
}
private static <V, E> List<E> createPath(MyBreadthFirstIterator<V, E> iter, V endVertex) {
List<E> path = new ArrayList<E>();
while (true) {
E edge = iter.getSpanningTreeEdge(endVertex);
if (edge == null) {
break;
}
path.add(edge);
endVertex = Graphs.getOppositeVertex(iter.getGraph(), edge, endVertex);
}
Collections.reverse(path);
return path;
}
private static class MyBreadthFirstIterator<V, E> extends BreadthFirstIterator<V, E> {
public MyBreadthFirstIterator(Graph<V, E> g, V startVertex) {
super(g, startVertex);
}
@Override
protected void encounterVertex(V vertex, E edge) {
super.encounterVertex(vertex, edge);
putSeenData(vertex, edge);
}
@SuppressWarnings("unchecked")
public E getSpanningTreeEdge(V vertex) {
return (E) getSeenData(vertex);
}
}
}
謝謝,這更接近我想要的,並會給我想要的靈魂。但是認爲它可能比遍歷圖更慢,因爲它需要額外的計算(這很重要,因爲實際上我的圖很大)。有沒有辦法通過廣度優先搜索遍歷圖形? – Niemand
@Niemand看我的編輯,我正在研究這樣的解決方案。 – Tunaki
謝謝!我會檢查這個代碼是否有效,但它確實是我想要的。編輯:開心10k點:) – Niemand