import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeSet;
import java.util.stream.Collectors;
class Ideone {
public static void main
(String[] args
) { test1();
test2();
}
public static void test1() {
Graph graph = new Graph();
graph.addEdge(0, 1, 4);
graph.addEdge(0, 2, 3);
graph.addEdge(1, 2, 1);
graph.addEdge(1, 3, 2);
graph.addEdge(2, 3, 4);
graph.addEdge(3, 4, 2);
graph.addEdge(4, 5, 6);
graph.startAt(0);
System.
out.
println(graph.
getPath(5)); }
public static void test2() {
Graph graph = new Graph();
graph.addEdge(0, 1, 4);
graph.addEdge(0, 2, 3);
graph.addEdge(1, 3, 2);
graph.addEdge(1, 2, 5);
graph.addEdge(2, 3, 7);
graph.addEdge(3, 4, 2);
graph.addEdge(4, 0, 4);
graph.addEdge(4, 1, 4);
graph.addEdge(4, 5, 6);
graph.startAt(0);
System.
out.
println(graph.
getPath(5)); }
}
final class Graph {
private static final class Node {
final int no;
Map<Node, Integer> edges = new HashMap<>();
Node[] path;
int pathWeight;
Node(int no) {
this.no = no;
}
}
private Map
<Integer, Node
> nodes
= new HashMap
<>();
public void addEdge(int sourceNo, int destinationNo, int weight) {
Node source = this.nodes.computeIfAbsent(sourceNo, Node::new);
Node dest = this.nodes.computeIfAbsent(destinationNo, Node::new);
source.edges.put(dest, weight);
dest.edges.put(source, weight);
}
public void startAt(int startNo) {
this.nodes.values().forEach(n -> n.path = null);
Node source = this.nodes.computeIfAbsent(startNo, Node::new);
source.path = new Node[] { source };
source.pathWeight = 0;
TreeSet
<Node
> pending
= new TreeSet
<>((a, b
) -> Integer.
compare(a.
pathWeight, b.
pathWeight)); pending.add(source);
while ((source = pending.pollFirst()) != null) {
for (Entry<Node, Integer> edge : source.edges.entrySet()) {
Node dest = edge.getKey();
int weight = source.pathWeight + edge.getValue();
if (dest.path == null || weight < dest.pathWeight
|| (weight == dest.pathWeight && source.path.length + 1 < dest.path.length)) {
if (dest.path != null)
pending.remove(dest);
dest.
path = Arrays.
copyOf(source.
path, source.
path.
length + 1); dest.path[source.path.length] = dest;
dest.pathWeight = weight;
pending.add(dest);
}
}
}
}
public String getPath
(int endNo
) { Node node = this.nodes.get(endNo);
return (node == null || node.path == null ? "Unreachable" :
Arrays.
stream(node.
path).
map(n
-> String.
valueOf(n.
no)).
collect(Collectors.
joining(" - ")) + " (distance: " + node.pathWeight + ")");
}
}
aW1wb3J0IGphdmEudXRpbC5BcnJheXM7CmltcG9ydCBqYXZhLnV0aWwuSGFzaE1hcDsKaW1wb3J0IGphdmEudXRpbC5NYXA7CmltcG9ydCBqYXZhLnV0aWwuTWFwLkVudHJ5OwppbXBvcnQgamF2YS51dGlsLlRyZWVTZXQ7CmltcG9ydCBqYXZhLnV0aWwuc3RyZWFtLkNvbGxlY3RvcnM7CgpjbGFzcyBJZGVvbmUgewoJcHVibGljIHN0YXRpYyB2b2lkIG1haW4oU3RyaW5nW10gYXJncykgewoJCXRlc3QxKCk7CgkJdGVzdDIoKTsKCX0KCXB1YmxpYyBzdGF0aWMgdm9pZCB0ZXN0MSgpIHsKCQlHcmFwaCBncmFwaCA9IG5ldyBHcmFwaCgpOwoJCWdyYXBoLmFkZEVkZ2UoMCwgMSwgNCk7CgkJZ3JhcGguYWRkRWRnZSgwLCAyLCAzKTsKCQlncmFwaC5hZGRFZGdlKDEsIDIsIDEpOwoJCWdyYXBoLmFkZEVkZ2UoMSwgMywgMik7CgkJZ3JhcGguYWRkRWRnZSgyLCAzLCA0KTsKCQlncmFwaC5hZGRFZGdlKDMsIDQsIDIpOwoJCWdyYXBoLmFkZEVkZ2UoNCwgNSwgNik7CgkJZ3JhcGguc3RhcnRBdCgwKTsKCQlTeXN0ZW0ub3V0LnByaW50bG4oZ3JhcGguZ2V0UGF0aCg1KSk7Cgl9CglwdWJsaWMgc3RhdGljIHZvaWQgdGVzdDIoKSB7CgkJR3JhcGggZ3JhcGggPSBuZXcgR3JhcGgoKTsKCQlncmFwaC5hZGRFZGdlKDAsIDEsIDQpOwoJCWdyYXBoLmFkZEVkZ2UoMCwgMiwgMyk7CgkJZ3JhcGguYWRkRWRnZSgxLCAzLCAyKTsKCQlncmFwaC5hZGRFZGdlKDEsIDIsIDUpOwoJCWdyYXBoLmFkZEVkZ2UoMiwgMywgNyk7CgkJZ3JhcGguYWRkRWRnZSgzLCA0LCAyKTsKCQlncmFwaC5hZGRFZGdlKDQsIDAsIDQpOwoJCWdyYXBoLmFkZEVkZ2UoNCwgMSwgNCk7CgkJZ3JhcGguYWRkRWRnZSg0LCA1LCA2KTsKCQlncmFwaC5zdGFydEF0KDApOwoJCVN5c3RlbS5vdXQucHJpbnRsbihncmFwaC5nZXRQYXRoKDUpKTsKCX0KfQpmaW5hbCBjbGFzcyBHcmFwaCB7Cglwcml2YXRlIHN0YXRpYyBmaW5hbCBjbGFzcyBOb2RlIHsKCQlmaW5hbCBpbnQgbm87CgkJTWFwPE5vZGUsIEludGVnZXI+IGVkZ2VzID0gbmV3IEhhc2hNYXA8PigpOwoJCU5vZGVbXSBwYXRoOwoJCWludCBwYXRoV2VpZ2h0OwoJCU5vZGUoaW50IG5vKSB7CgkJCXRoaXMubm8gPSBubzsKCQl9Cgl9CgoJcHJpdmF0ZSBNYXA8SW50ZWdlciwgTm9kZT4gbm9kZXMgPSBuZXcgSGFzaE1hcDw+KCk7CgoJcHVibGljIHZvaWQgYWRkRWRnZShpbnQgc291cmNlTm8sIGludCBkZXN0aW5hdGlvbk5vLCBpbnQgd2VpZ2h0KSB7CgkJTm9kZSBzb3VyY2UgPSB0aGlzLm5vZGVzLmNvbXB1dGVJZkFic2VudChzb3VyY2VObywgTm9kZTo6bmV3KTsKCQlOb2RlIGRlc3QgPSB0aGlzLm5vZGVzLmNvbXB1dGVJZkFic2VudChkZXN0aW5hdGlvbk5vLCBOb2RlOjpuZXcpOwoJCXNvdXJjZS5lZGdlcy5wdXQoZGVzdCwgd2VpZ2h0KTsKCQlkZXN0LmVkZ2VzLnB1dChzb3VyY2UsIHdlaWdodCk7Cgl9CgoJcHVibGljIHZvaWQgc3RhcnRBdChpbnQgc3RhcnRObykgewoJCXRoaXMubm9kZXMudmFsdWVzKCkuZm9yRWFjaChuIC0+IG4ucGF0aCA9IG51bGwpOwoJCU5vZGUgc291cmNlID0gdGhpcy5ub2Rlcy5jb21wdXRlSWZBYnNlbnQoc3RhcnRObywgTm9kZTo6bmV3KTsKCQlzb3VyY2UucGF0aCA9IG5ldyBOb2RlW10geyBzb3VyY2UgfTsKCQlzb3VyY2UucGF0aFdlaWdodCA9IDA7CgkJVHJlZVNldDxOb2RlPiBwZW5kaW5nID0gbmV3IFRyZWVTZXQ8PigoYSwgYikgLT4gSW50ZWdlci5jb21wYXJlKGEucGF0aFdlaWdodCwgYi5wYXRoV2VpZ2h0KSk7CgkJcGVuZGluZy5hZGQoc291cmNlKTsKCQl3aGlsZSAoKHNvdXJjZSA9IHBlbmRpbmcucG9sbEZpcnN0KCkpICE9IG51bGwpIHsKCQkJZm9yIChFbnRyeTxOb2RlLCBJbnRlZ2VyPiBlZGdlIDogc291cmNlLmVkZ2VzLmVudHJ5U2V0KCkpIHsKCQkJCU5vZGUgZGVzdCA9IGVkZ2UuZ2V0S2V5KCk7CgkJCQlpbnQgd2VpZ2h0ID0gc291cmNlLnBhdGhXZWlnaHQgKyBlZGdlLmdldFZhbHVlKCk7CgkJCQlpZiAoZGVzdC5wYXRoID09IG51bGwgfHwgd2VpZ2h0IDwgZGVzdC5wYXRoV2VpZ2h0CgkJCQkgICAgICAgICAgICAgICAgICAgICAgfHwgKHdlaWdodCA9PSBkZXN0LnBhdGhXZWlnaHQgJiYgc291cmNlLnBhdGgubGVuZ3RoICsgMSA8IGRlc3QucGF0aC5sZW5ndGgpKSB7CgkJCQkJaWYgKGRlc3QucGF0aCAhPSBudWxsKQoJCQkJCQlwZW5kaW5nLnJlbW92ZShkZXN0KTsKCQkJCQlkZXN0LnBhdGggPSBBcnJheXMuY29weU9mKHNvdXJjZS5wYXRoLCBzb3VyY2UucGF0aC5sZW5ndGggKyAxKTsKCQkJCQlkZXN0LnBhdGhbc291cmNlLnBhdGgubGVuZ3RoXSA9IGRlc3Q7CgkJCQkJZGVzdC5wYXRoV2VpZ2h0ID0gd2VpZ2h0OwoJCQkJCXBlbmRpbmcuYWRkKGRlc3QpOwoJCQkJfQoJCQl9CgkJfQoJfQoKCXB1YmxpYyBTdHJpbmcgZ2V0UGF0aChpbnQgZW5kTm8pIHsKCQlOb2RlIG5vZGUgPSB0aGlzLm5vZGVzLmdldChlbmRObyk7CgkJcmV0dXJuIChub2RlID09IG51bGwgfHwgbm9kZS5wYXRoID09IG51bGwgPyAiVW5yZWFjaGFibGUiIDoKCQkgICAgICAgIEFycmF5cy5zdHJlYW0obm9kZS5wYXRoKS5tYXAobiAtPiBTdHJpbmcudmFsdWVPZihuLm5vKSkuY29sbGVjdChDb2xsZWN0b3JzLmpvaW5pbmcoIiAtICIpKQoJCSAgICAgICAgKyAiIChkaXN0YW5jZTogIiArIG5vZGUucGF0aFdlaWdodCArICIpIik7Cgl9Cn0=