I have an interesting question at hand. I want to solve a problem of starting from a source vertex of a weighted graph, and find out all possible paths that lead back to it.
For eg: Consider a directed graph above:
Expected Output If I start from Source=A:
1) A -> C -> D -> B-> A
2) A -> B -> A
3) A -> D -> B -> A
Note:
a) The graph will be weighted and I'am finding the sum(not necessarily minimum sum) of the edges as I traverse.
b) Planning to represent the graph using a matrix, and the graph may be Cyclic at some places.
b) Which is the most efficient code that'll solve this? I know about BFS and DFS, but they dont calculate round trips!
Current DFS CODE: (adjacency graph)
void dfs(int cost[][20],int v[],int n, int j)
{
int i;
v[j]=1;
printf("Vistiing %d\n",j);
for(i=0;i<n;i++)
if(cost[j][i]==1 && v[i]==0)
dfs(cost,v,n,i
);
}
This can be solved by modifying DFS (or BFS).
Consider DFS.
Once you visit the nodes mark it as visited. Once you return from it, mark it un-visited so that other paths can be recognized.
Your example:
Start from A.
Choose a path.
A->B->A.
Return to B. No other paths.
Return to A. Mark B unvisited. Choose another path.
A->D->B->A.
Return to B. No other paths.
Return to D. Mark B unvisited. No other paths.
Return to A. Mark D unvisited. Choose another path.
A->C->D->B->A.
Note: The important thing here is to mark the nodes un-visited.
This sounds like a nice application case for Backtracking:
Start with the desired node
If you reached the start node for the second time, return the result
Otherwise: For each neighbor
Add the neighbor to the current path
Do the recursion
Remove the neighbor from the current path
This is implemented here as an example. Of course, this (particularly the graph data structure) is only a quick sketch to show that the idea is feasible, in a MCVE:
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class GraphRoundTrips
{
static class Vertex
{
String name;
Vertex(String name)
{
this.name = name;
}
#Override
public String toString()
{
return name;
}
}
static class Edge
{
Vertex v0;
Vertex v1;
Edge(Vertex v0, Vertex v1)
{
this.v0 = v0;
this.v1 = v1;
}
#Override
public String toString()
{
return "("+v0+","+v1+")";
}
}
static class Graph
{
List<Vertex> vertices = new ArrayList<Vertex>();
List<Edge> edges = new ArrayList<Edge>();
void addVertex(Vertex v)
{
vertices.add(v);
}
void addEdge(Edge e)
{
edges.add(e);
}
List<Vertex> getOutNeighbors(Vertex v)
{
List<Vertex> result = new ArrayList<Vertex>();
for (Edge e : edges)
{
if (e.v0.equals(v))
{
result.add(e.v1);
}
}
return result;
}
}
public static void main(String[] args)
{
Vertex A = new Vertex("A");
Vertex B = new Vertex("B");
Vertex C = new Vertex("C");
Vertex D = new Vertex("D");
Graph graph = new Graph();
graph.addVertex(A);
graph.addVertex(B);
graph.addVertex(C);
graph.addVertex(D);
graph.addEdge(new Edge(A,C));
graph.addEdge(new Edge(A,D));
graph.addEdge(new Edge(A,B));
graph.addEdge(new Edge(B,A));
graph.addEdge(new Edge(C,D));
graph.addEdge(new Edge(D,B));
compute(graph, A, null, new LinkedHashSet<Vertex>());
}
private static void compute(Graph g, Vertex startVertex,
Vertex currentVertex, Set<Vertex> currentPath)
{
if (startVertex.equals(currentVertex))
{
List<Vertex> path = new ArrayList<Vertex>();
path.add(startVertex);
path.addAll(currentPath);
System.out.println("Result "+path);
}
if (currentVertex == null)
{
currentVertex = startVertex;
}
List<Vertex> neighbors = g.getOutNeighbors(currentVertex);
for (Vertex neighbor : neighbors)
{
if (!currentPath.contains(neighbor))
{
currentPath.add(neighbor);
compute(g, startVertex, neighbor, currentPath);
currentPath.remove(neighbor);
}
}
}
}
Related
How to put the results of this if condition in a array list?
import java.util.ArrayList;
import java.util.Scanner;
public class GreatestCommonDivisor {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("Please enter a value whose GCD to be computed");
int number = scan.nextInt();
for(int i=1;i<=10;i++) {
if(number%i==0) {
ArrayList<Integer> arr = new ArrayList<Integer>(number) {
}
}
}
}
}
GCD stands for Greatest Common Divisor...which finds the greatest number that divides all the numbers that you specify, but in your code I just see one number.
So from your code I get the idea that you wish to find all the numbers less than 10 (inclusive) that divide number and store those numbers in an arraylist. Assuming my assumption to be correct you can do the following.
Declare your arraylist before the loop:
ArrayList<Integer>arr = new ArrayList<Integer>()
Now run the loop:
for(int i=1;i<=10;i++){
if(number%i==0){
v.add(i);
}
}
In a social media, suppose each user is represented like below:
public class User {
private int userId;
private List<User> friendsList;
User(int id) {
this.userID = id;
this.friendsList = new LinkedList<>();
}
void addFriend(User a) {
this.friendsList.add(a);
}
int getUserId() {
return this.userID;
}
List<User> getFriendsList() {
return this.friendsList;
}
}
if A and B are friends(A->B), then A will be added to B's friend list and B will be added to A's friend list.
A.addFriend(B);
B.addFriend(A);
How i can efficiently find two users X and Y are connected by using Java 8 steam methods ?
ie if X->p->q->r->s->Y, then
bool isConnected(User X, User Y) should return true
Here X and Y are connected through common friends p, q, r and s.
You would need a way to keep track of the object that was visited or else you will go in loops.
public bool NodeVisited { get; private set; }
boolean isConnected(User a, User b){
for(final User u : a.getFriendsList()){
if(NodeVisited == false){
NodeVisited = true;
if(u.getUserId() == b.getUserId() || isConnected(u, b)){
return true;
}
}
else continue;
}
return false;
}
The close problem to "Find the shortest way (if any) between 2 points in a labyrinth."
Main idea:
Spread 2 waves from 2 points (or 2 friends) which cover near points (friends)
Remember only(!) previous layers of points (friends) to restrict the future spreading out of the wave in that directions
After each spreading out step check wawes intersection for common points (friends)
Repeat until getting intersections of waves or 1 wave will be stopped:
there are no new directions to spread except in backward directions from the previous step.
P.S.:
The most optimal algorithm involves "several" (depends on data) spots of wave spreading processes.
https://github.com/Dimoniada/FriendsProblem
You don't really have to use streams, but just a simple for-loop and recursion:
boolean isConnected(User a, User b){
for(final User u : a.getFriendsList()){
if(u.getUserId() == b.getUserId() || isConnected(u, b)){
return true;
}
}
return false;
}
If you still want to use streams, you can use this snippet (still uses recursion though):
boolean isConnected(User a, User b){
return a.getFriendsList()
.stream()
.anyMatch(u -> u.getUserId() == b.getUserId() || isConnected(u, b));
}
Is it possible to sum up the nodes of a tree using Java 8 streams, if possible in a one liner ?
Here is a node class
public class Node
{
private int nodeNum;
ArrayList<Node> children = new ArrayList<>();
public Node(int num)
{
this.nodeNum = num;
}
public int getNodeNum()
{
return nodeNum;
}
public boolean addNode(Node node)
{
return children.add(node);
}
public ArrayList<Node> getNodes()
{
return this.children;
}
}
Normal way to solve this is using a recursion and sum up the node , like the code below.
int getNodeSum(Node node)
{
int total = 0;
if(node.children.isEmpty())
return node.getNodeNum();
else
{
for(Node tempNode:node.children)
{
total+= getNodeSum(tempNode);
}
return total+node.getNodeNum();
}
}
We can use streams to sum up the immediate child nodes but I'm not getting how to move deep and do it recursively using Streams.
This code only solves the problem to a single level. Any ideas?
total = list.stream().filter(Node -> node.children.isEmpty()).map(Node:: getNodeNum).reduce(node.getNodeNum(), (a,b) -> a+b);
One solution to your problem would be to use recursion along with Stream.flatMap.
First, you'd need to add the following helper method to your Node class:
public Stream<Node> allChildren() {
return Stream.concat(
Stream.of(this),
this.children.stream().flatMap(Node::allChildren)); // recursion here
}
This returns a Stream<Node> whose elements are this node and all its descendant nodes.
Then, you could rewrite your getNodeSum method as follows:
int getNodeSum(Node node) {
return node.allChildren()
.mapToInt(Node::getNodeNum)
.sum();
}
This uses the above defined Node.allChildren method along with the Stream.mapToInt and IntStream.sum methods to calculate the total sum.
Alternatively, you could have a Function<Node, Stream<Node>> descendants attribute in your Node class that performs the recursion in place:
private Function<Node, Stream<Node>> descendants =
node -> Stream.concat(
Stream.of(node),
node.children.stream()
.flatMap(this.descendants)); // recursion here: function invoked again
This is a recursive lambda expression, since the function you are defining is at both sides of the = sign. This kind of lambda expressions are allowed only as attributes of a class, i.e. you cannot assign a recursive lambda expression to a local variable.
With that recursive function in place, you could rewrite the allChildren method as follows:
public Stream<Node> allChildren() {
return descendants.apply(this);
}
Finally, the code for your getNodeSum method would be identical to the previous version:
int getNodeSum(Node node) {
return node.allChildren()
.mapToInt(Node::getNodeNum)
.sum();
}
Note: while this approach might result attractive for some people, it might have some drawbacks, i.e. now every instance of the Node class has the descendants attribute, despite not being needed at all. You could circumvect this i.e. by having a Tree class with this recursive function as an attribute, and Node being an inner class (with the descendants attribute removed).
You need to add recusive method for Node class, which wil be join child streams
public Stream<Node> recursiveConcat() {
return Stream.concat(
Stream.of(this),
children.stream().flatMap(Node::recursiveConcat));
}
Then do -
root.recusiveConcat().mapToInt(Node::getNodeNum).sum()
whole code
public class Node {
private int nodeNum;
ArrayList<Node> children = new ArrayList<>();
public Node(int num) {
this.nodeNum = num;
}
public int getNodeNum() {
return nodeNum;
}
public boolean addNode(Node node) {
return children.add(node);
}
public ArrayList<Node> getNodes() {
return this.children;
}
public Stream<Node> recursiveConcat() {
return Stream.concat(
Stream.of(this),
children.stream().flatMap(Node::recursiveConcat));
}
}
Node root = new Node(1);
Node node1 = new Node(2);
Node node2 = new Node(3);
Node node3 = new Node(4);
node2.addNode(node3);
node1.addNode(node2);
root.addNode(node1);
System.out.println(root.recursiveConcat().mapToInt(Node::getNodeNum).sum());
Given a directed graph with
A root node
Some leaves nodes
Multiple nodes can be connected to the same node
Cycles can exist
We need to print all the paths from the root node to all the leaves nodes. This is the closest question I got to this problem
Find all paths between two graph nodes
If you actually care about ordering your paths from shortest path to longest path then it would be far better to use a modified A* or Dijkstra Algorithm. With a slight modification the algorithm will return as many of the possible paths as you want in order of shortest path first. So if what you really want are all possible paths ordered from shortest to longest then this is the way to go. The code I suggested above would be much slower than it needs to be if you care about ordering from shortest to longest, not to mention would take up more space then you'd want in order to store every possible path at once.
If you want an A* based implementation capable of returning all paths ordered from the shortest to the longest, the following will accomplish that. It has several advantages. First off it is efficient at sorting from shortest to longest. Also it computes each additional path only when needed, so if you stop early because you dont need every single path you save some processing time. It also reuses data for subsequent paths each time it calculates the next path so it is more efficient. Finally if you find some desired path you can abort early saving some computation time. Overall this should be the most efficient algorithm if you care about sorting by path length.
import java.util.*;
public class AstarSearch {
private final Map<Integer, Set<Neighbor>> adjacency;
private final int destination;
private final NavigableSet<Step> pending = new TreeSet<>();
public AstarSearch(Map<Integer, Set<Neighbor>> adjacency, int source, int destination) {
this.adjacency = adjacency;
this.destination = destination;
this.pending.add(new Step(source, null, 0));
}
public List<Integer> nextShortestPath() {
Step current = this.pending.pollFirst();
while( current != null) {
if( current.getId() == this.destination )
return current.generatePath();
for (Neighbor neighbor : this.adjacency.get(current.id)) {
if(!current.seen(neighbor.getId())) {
final Step nextStep = new Step(neighbor.getId(), current, current.cost + neighbor.cost + predictCost(neighbor.id, this.destination));
this.pending.add(nextStep);
}
}
current = this.pending.pollFirst();
}
return null;
}
protected int predictCost(int source, int destination) {
return 0; //Behaves identical to Dijkstra's algorithm, override to make it A*
}
private static class Step implements Comparable<Step> {
final int id;
final Step parent;
final int cost;
public Step(int id, Step parent, int cost) {
this.id = id;
this.parent = parent;
this.cost = cost;
}
public int getId() {
return id;
}
public Step getParent() {
return parent;
}
public int getCost() {
return cost;
}
public boolean seen(int node) {
if(this.id == node)
return true;
else if(parent == null)
return false;
else
return this.parent.seen(node);
}
public List<Integer> generatePath() {
final List<Integer> path;
if(this.parent != null)
path = this.parent.generatePath();
else
path = new ArrayList<>();
path.add(this.id);
return path;
}
#Override
public int compareTo(Step step) {
if(step == null)
return 1;
if( this.cost != step.cost)
return Integer.compare(this.cost, step.cost);
if( this.id != step.id )
return Integer.compare(this.id, step.id);
if( this.parent != null )
this.parent.compareTo(step.parent);
if(step.parent == null)
return 0;
return -1;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Step step = (Step) o;
return id == step.id &&
cost == step.cost &&
Objects.equals(parent, step.parent);
}
#Override
public int hashCode() {
return Objects.hash(id, parent, cost);
}
}
/*******************************************************
* Everything below here just sets up your adjacency *
* It will just be helpful for you to be able to test *
* It isnt part of the actual A* search algorithm *
********************************************************/
private static class Neighbor {
final int id;
final int cost;
public Neighbor(int id, int cost) {
this.id = id;
this.cost = cost;
}
public int getId() {
return id;
}
public int getCost() {
return cost;
}
}
public static void main(String[] args) {
final Map<Integer, Set<Neighbor>> adjacency = createAdjacency();
final AstarSearch search = new AstarSearch(adjacency, 1, 4);
System.out.println("printing all paths from shortest to longest...");
List<Integer> path = search.nextShortestPath();
while(path != null) {
System.out.println(path);
path = search.nextShortestPath();
}
}
private static Map<Integer, Set<Neighbor>> createAdjacency() {
final Map<Integer, Set<Neighbor>> adjacency = new HashMap<>();
//This sets up the adjacencies. In this case all adjacencies have a cost of 1, but they dont need to.
addAdjacency(adjacency, 1,2,1,5,1); //{1 | 2,5}
addAdjacency(adjacency, 2,1,1,3,1,4,1,5,1); //{2 | 1,3,4,5}
addAdjacency(adjacency, 3,2,1,5,1); //{3 | 2,5}
addAdjacency(adjacency, 4,2,1); //{4 | 2}
addAdjacency(adjacency, 5,1,1,2,1,3,1); //{5 | 1,2,3}
return Collections.unmodifiableMap(adjacency);
}
private static void addAdjacency(Map<Integer, Set<Neighbor>> adjacency, int source, Integer... dests) {
if( dests.length % 2 != 0)
throw new IllegalArgumentException("dests must have an equal number of arguments, each pair is the id and cost for that traversal");
final Set<Neighbor> destinations = new HashSet<>();
for(int i = 0; i < dests.length; i+=2)
destinations.add(new Neighbor(dests[i], dests[i+1]));
adjacency.put(source, Collections.unmodifiableSet(destinations));
}
}
The output from the above code is the following:
[1, 2, 4]
[1, 5, 2, 4]
[1, 5, 3, 2, 4]
Notice that each time you call nextShortestPath() it generates the next shortest path for you on demand. It only calculates the extra steps needed and doesnt traverse any old paths twice. Moreover if you decide you dont need all the paths and end execution early you've saved yourself considerable computation time. You only compute up to the number of paths you need and no more.
Finally it should be noted that the A* and Dijkstra algorithms do have some minor limitations, though I dont think it would effect you. Namely it will not work right on a graph that has negative weights.
Here is a link to JDoodle where you can run the code yourself in the browser and see it working. You can also change around the graph to show it works on other graphs as well: http://jdoodle.com/a/ukx
I am implementing the code to get the shorted path in a directed graph as shown below using Dijkstra's algorithm?
my question is
how to define the adjacency list for a vertex?
in my current code below, I have considered only the outgoing edges to the part of the adjacency list
Does Dijkstra's alogithm fail if there is a cyclic pattern with in the graph? for example, ABD forms a cycle below
if there is no outgoing edges from a vertex, then there is no shortest path from that vertex as the source, example: for the graph below, If I want to find the shortest path from F to A, there is none.
should Dijsktra'a algorithm takes care of that?
I have implemented Dijsktra's algorithm, but I am not pasting that code here. After clarifying these doubts, I will post a seperate question on my problems with Dijkstra's implementation.
my current code for Vertex, Edge and Graph is below. As you can notice, I have defined the vertex and adjacency list for the above image. please pass your comments if the adjcacency list is correct.
eg: vertex F has no adjacency list as there are no outgoing edges from it.
class Vertex implements Comparable<Vertex>
{
public final String name;
public Edge[] adjacencies;
public double minDistance = Double.POSITIVE_INFINITY;
public Vertex previous;
public Vertex(String argName) { name = argName; }
public String toString() { return name; }
public int compareTo(Vertex other)
{
return Double.compare(minDistance, other.minDistance);
}
}
class Edge
{
public final Vertex target;
public final double weight;
public Edge(Vertex argTarget, double argWeight)
{ target = argTarget; weight = argWeight; }
}
public class Graph {
public static void main(String[] args) {
Vertex A = new Vertex("A");
Vertex B = new Vertex("B");
Vertex C = new Vertex("C");
Vertex D = new Vertex("D");
Vertex E = new Vertex("E");
Vertex F = new Vertex("F");
Vertex G = new Vertex("G");
A.adjacencies = new Edge[]{ new Edge(B, 1)};
B.adjacencies = new Edge[]{ new Edge(C, 3), new Edge(D, 2)};
C.adjacencies= new Edge[]{new Edge(D, 1),new Edge(E, 4)};
D.adjacencies= new Edge[]{new Edge(E, 2),new Edge(A, 2) };
E.adjacencies= new Edge[]{new Edge(F, 3) };
//F.adjacencies= null;
G.adjacencies= new Edge[]{new Edge(D, 1)};
}
}
Using only outgoing edges works.
No. Good implementations of the algorithm doesn't have problems with cycles. In the algorithm, it's impossible to have a problem with cycles because the nodes are "eliminated" increasingly, and lots of edges are eliminated.
Yes. The algorithm will take care of that. Before starting, you must be sure that all intermediate information is set correctly, for example, you need to be able to identify if nodes were removed. In the algorithm you need to select the node to start with, and if the node doesn't have adjacent nodes, then the other nodes (e.g. A), will have the previous attribute set to null. Would be easier to implement F.adjacencies = new Edge[0];