Java Detecting a cyclic directed Graph - java

I am currently trying to write a procedure to check whether a directed graph is cyclic or not. I am not sure what i did wrong (it may be well possible that I did everything wrong, so please StackOverflow, show me my stupidity!). I'd be thankful for any kind of help as I've come to the point where I don't know what could be the problem.
The input is an adjacency list such as:
0: 2 4
1: 2 4
2: 3 4
3: 4
4: 0 1 2 3
(0 directs to 2 and 4; 1 directs to 2 and 4 and so on...)
The idea is that I check whether the node I am checking is 'grey' (partially explored) or not. If it is, it must be a back edge and thus a cyclic graph. Black edges are always explored or cross-edges, so this shouldn't trigger a cyclic message. I am aiming to do depth first search
If A-->B and B-->A, this should not trigger a message about cyclic (but A--> B, B-->C, C-->A should).
hasCycle calls hasCycleInSubgraph which calls itself recursively through the Adjency List of the Graph.
class qs {
private ArrayList<Integer>[] adjList;
private Stack<Integer> stack;
private ArrayList<Integer> whiteHat;
private ArrayList<Integer> greyHat;
private ArrayList<Integer> blackHat;
public qs(ArrayList<Integer>[] graph) {
this.adjList = graph;
this.stack = new Stack();
this.whiteHat = new ArrayList<Integer>();
this.greyHat = new ArrayList<Integer>();
this.blackHat = new ArrayList<Integer>();
for (Integer h = 0; h < adjList.length; h++) {
whiteHat.add(h);
}
}
public boolean hasCycle() {
for (Integer i = 0; i < adjList.length; i++) {
// System.out.print("Local root is: ");
// System.out.println(i);
whiteHat.remove(i);
greyHat.add(i);
if (hasCycleInSubgraph(i) == true) {
return true;
}
greyHat.remove(i);
blackHat.add(i);
}
return false;
}
public boolean hasCycleInSubgraph(Integer inp) {
if (blackHat.contains(inp)) {
return false;
}
for (Integer branch : adjList[inp]) {
// System.out.print("Adj is: ");
// System.out.println(branch);
if ( greyHat.contains(branch) && !inp.equals(branch) ) {
return true;
}
whiteHat.remove(branch);
greyHat.add(branch);
if ( hasCycleInSubgraph(branch) == true ) {
return true;
}
greyHat.remove(branch);
blackHat.add(branch);
}
return false;
}
}

You are over-complicating it: a cycle can be detected via a depth-first search: from any given node, walk to each of the connected nodes; if you arrive back at an already-visited node, you've got a cycle.
class qs {
private final ArrayList<Integer>[] graph;
qs(ArrayList<Integer>[] graph) {
this.graph = graph;
}
boolean hasCycle() {
List<Integer> visited = new ArrayList<>();
for (int i = 0; i < graph.length; ++i) {
if (hasCycle(i, visited)) {
return true;
}
}
}
private boolean hasCycle(int node, List<Integer> visited) {
if (visited.contains(node)) {
return true;
}
visited.add(node);
for (Integer nextNode : graph[node]) {
if (hasCycle(nextNode, visited)) {
return true;
}
}
visited.remove(visited.length() - 1);
return false;
}
}
If you want to detect cycles longer than a given length, just check the depth of the recursion:
if (visited.contains(node) && visited.size() > 2) {
Note that this does not require any state to be kept, aside from what is in the stack. Relying upon mutable state makes the code thread-unsafe (e.g. that two threads calling hasCycle at the same time would interfer with each other), and so should be avoided - even if you don't expect the code to be used in a multi-threaded way now, it avoids problems down the line.

Related

I am getting wrong answer for prime path problem can anyone help me in finding the issue?

Problem Link: https://www.spoj.com/problems/PPATH/
Brief explanation of the problem,
1) Construct a graph with prime numbers between 1000 and 9999.
2) Add an undirected edge between two numbers 'a' and 'b', if they differ only by one digit.
EX: 1033 and 1733 differ only by one digit.
3) In that graph we need to find the length of the shortest path from the given source to the given destination.
I have solved the above problem by constructing a graph using the prime number between 1000 and 9999, by connecting numbers that differ only by one digit. EX: 1033 and 1733 differ only by one digit.
I have used DFS along with memorisation to find the shortest path.
For some input i am getting wrong answer, 1 greater than the actual value, since there are 1000 nodes i can't able to figure out the issue. It will be so helpful if someone help me to figure out the issue.
I know this problem can be solved by BFS, but i need to know what's wrong with this problem.
test cases when the below program prints wrong answer
1
7573 9973
Actual answer : 4
My code output : 5
(I have found the actual answer by submitting a BFS approach to the problem and it got Accepted in SPOJ).
import java.util.*;
import java.lang.*;
import java.io.*;
class FireEscapeRoutes_FIRESC {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
public static void main(String[] args) throws Exception{
int t = 1;
while (t--!=0){
int source = 7573;
int destination = 9973;
List<Integer> fourDigitPrimeNos = new ArrayList<>();
for(int i=1001;i<=9999;i++){
if(isPrime(i)){
fourDigitPrimeNos.add(i);
//System.out.println(i);
}
}
Graph graph = new Graph(fourDigitPrimeNos.size());
/*
If two number 'a' and 'b' differ only by one digit then an edge is added.
*/
for (int i=0;i<fourDigitPrimeNos.size();i++){
for (int j=i+1;j<fourDigitPrimeNos.size();j++){
if(isSingleDistnace(fourDigitPrimeNos.get(i),fourDigitPrimeNos.get(j))){
graph.add(fourDigitPrimeNos.get(i),fourDigitPrimeNos.get(j));
}
}
}
//System.out.println(graph.graph);
Long minPath = graph.getShortestPath(source,destination);
if(minPath!=Long.MAX_VALUE){
System.out.println(minPath);
}else{
System.out.println("Impossible");
}
}
}
static boolean isSingleDistnace(int a, int b){
String as = a+"";
String bs = b+"";
int ds = 0;
for (int i=0;i<as.length();i++){
if(!(as.charAt(i)==bs.charAt(i))){
if(ds>=1){
return false;
}
ds++;
}
}
if(ds==0){
return false;
}
return true;
}
static boolean isPrime(int n){
for (int i=2;i<=Math.sqrt(n);i++){
if(n%i==0){
return false;
}
}
return true;
}
}
class Graph{
int noOfVertices;
HashMap<Integer,List<Integer>> graph;
Graph(int v){
noOfVertices = v;
graph = new HashMap<Integer,List<Integer>>();
}
void add(int u,int v){
if (!graph.containsKey(u)){
graph.put(u,new ArrayList<>());
}
if(!graph.containsKey(v)){
graph.put(v,new ArrayList<>());
}
graph.get(u).add(v);
graph.get(v).add(u);
}
Long getShortestPath(int start, int dest){
HashMap<Integer,Long> visitedVsMinCost = new HashMap<>();
Long min = Long.MAX_VALUE;
min = getShortestPathUtil(start,dest,visitedVsMinCost);
return min-1;
}
Long getShortestPathUtil(Integer start,Integer dest,HashMap<Integer,Long> visitedVsMinCost){
if(start.equals(dest)){
return 1l;
}
visitedVsMinCost.put(start, Long.MAX_VALUE);
List<Integer> frnds = graph.get(start);
Long min = Long.MAX_VALUE;
for (Integer iThFrind:frnds){
if(!visitedVsMinCost.containsKey(iThFrind)){
Long shortestPathUtil = getShortestPathUtil(iThFrind, dest, visitedVsMinCost);
//System.out.println(shortestPathUtil + " min " + min);
min = Math.min(min, shortestPathUtil);
}else {
if(!visitedVsMinCost.get(iThFrind).equals(Long.MAX_VALUE)) {
min = Math.min(min, visitedVsMinCost.get(iThFrind)+1);
}
}
}
visitedVsMinCost.put(start,min);
//System.out.println(min);
if (min.equals(Long.MAX_VALUE)){
return min;
}
return min+1;
}
}
NOTE: This below Part is to explain why my code works on the situation mentioned by #c0der. Since i can't able to comment more characters i am editting this question. To understand approach you can use this below part.
I can understand it is difficult to debug the code, so i try to explain my approach using the graph mentioned by #coder answer and
above code work fine in the scenario you mentioned.
Start = 1 and destination= 5, shortest path = 2 (1->4->5)
1) if DFS traverses through `1->2->3->4->5' and reached the destination '5' it return '1' to the '4'th node.
2) now the '4'th node memorise the returned value '1'. (This means between 4 and 5, there is one node, including destination, excluding the source 4).
2.1) Then it returns '2'(1+1) to the '3'rd node. and '3'rd node memorise the value '2'. (This means between 3rd node and destination(5) node , there is 2 node, in the shortest path. including destination, excluding source 3
3) similiarly call will go back to '1'.
4) then '1'st node, calls '4'th node and see it is visited before, so it takes the memorized value of '4' th node which is '1' and it returns '2' to '1'.
Debugging of the code posted is a long task.
However DFS is not the right tool for the job.
To visualize why DFS is not a good tool to find the shortest path consider the following simple graph:
If DSF happens to start by traversing nodes 1->2->3->4->5 the shortest path 1->4->5
will not be traversed because 4 is marked as visited.
This may be the reason why DFS along with memorisation is unable to find the shortest path.
Edit:
The following is a modified version of your code: it returns the actual shortest path found, if any.
This may help in debugging.
If finds the shortest path by performing DFS to traverse all possible paths and keeping the shortest one.
It is not optimized in the sense that if there are loops in the graph it may recalculate a path that has already been calculated before. You may want to add memorization of calculated pathes to make it more efficient.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
class FireEscapeRoutes_FIRESC {
public static void main(String[] args) throws Exception{
List<Integer> fourDigitPrimeNos = new ArrayList<>();
for(int i=1001; i<=9999; i++){
if(isPrime(i)){
fourDigitPrimeNos.add(i);
}
}
Graph graph = new Graph();
/*
If two number 'a' and 'b' differ only by one digit then an edge is added.
*/
for (int i=0;i<fourDigitPrimeNos.size();i++){
for (int j=i+1;j<fourDigitPrimeNos.size();j++){
if(isSingleDistnace(fourDigitPrimeNos.get(i),fourDigitPrimeNos.get(j))){
graph.add(fourDigitPrimeNos.get(i),fourDigitPrimeNos.get(j));
}
}
}
int source = 1033;
int destination = 8179; //expected 6 : 1033 1733 3733 3739 3779 8779 8179
/* more test cases
int source = 7573;
int destination = 9973; //expected 5
int source = 1373;
int destination = 8017; //expected 7
int source = 1033;
int destination = 1033; //expected 1
*/
List<Integer> shortestPath = graph.getShortestPath(source,destination);
if(shortestPath != null){
System.out.println("\nPath Found :"+ shortestPath);
System.out.println("Path length: "+shortestPath.size());
}else{
System.out.println("Impossible");
}
}
static boolean isSingleDistnace(int a, int b){
String as = a+"";
String bs = b+"";
int ds = 0;
for (int i=0;i<as.length();i++){
if(!(as.charAt(i)==bs.charAt(i))){
if(ds>=1)
return false;
ds++;
}
}
if(ds==0) return false;
return true;
}
static boolean isPrime(int n){
if (n <= 1) return false; //make sure it is positive
for (int i=2;i<=Math.sqrt(n);i++){
if(n%i==0)
return false;
}
return true;
}
}
class Graph{
private final HashMap<Integer,List<Integer>> graph;
//measure time and print out some progress indication
private static long startTime, printime;
private static long HEART_BEAT = 15000;
Graph(){
graph = new HashMap<>();
}
void add(int u,int v){
if (!graph.containsKey(u)){
graph.put(u,new ArrayList<>());
}
if(!graph.containsKey(v)){
graph.put(v,new ArrayList<>());
}
graph.get(u).add(v);
graph.get(v).add(u);
}
List<Integer> getShortestPath(int start, int dest){
System.out.print("Working ");
startTime = System.currentTimeMillis();
List<Integer> path = new ArrayList<>();
path = getShortestPathUtil(start,dest, Integer.MAX_VALUE, path);
System.out.println("\n run time in minutes " + (double) (System.currentTimeMillis() - startTime) /60000);
return path;
}
List<Integer> getShortestPathUtil(int start,int dest,int minLengthFound, List<Integer> path){
if(System.currentTimeMillis() - printime >= HEART_BEAT ){
System.out.print(".");
printime = System.currentTimeMillis();
}
if(path.contains(start)) return null; //prevent loops
path.add(start);
if(start == dest) return path;
//stop traverse if path is longer than the shortest one found earlier
if(minLengthFound != Integer.MAX_VALUE && path.size() >= minLengthFound) return null;
List <Integer> keepShortestPathFound = null;
for (int neighbor : graph.get(start)){
if(path.contains(neighbor)) {
continue;
}
List<Integer> shortestPathFromNeighbor = getShortestPathUtil(neighbor, dest, minLengthFound, new ArrayList<>(path));
if(shortestPathFromNeighbor != null && shortestPathFromNeighbor.contains(dest) &&
shortestPathFromNeighbor.size() < minLengthFound){
keepShortestPathFound = shortestPathFromNeighbor;
minLengthFound = shortestPathFromNeighbor.size();
}
}
return keepShortestPathFound;
}
}

All possible ways to reach an ending position

http://www.cstutoringcenter.com/problems/problems.php?id=103
For those who doesn't want to click it, it basically says there's a stepping stone, "-" and soldier "#", soldiers can only move right. If the soldier is behind another soldier, he must wait for the soldier to move first. The ending condition is when all soldiers reaches the end.
The number of ways 2 soldier can move across 5 stepping stones.
1) ##--- #-#-- -##-- -#-#- --##- --#-# ---##
2) ##--- #-#-- -##-- -#-#- -#--# --#-# ---##
3) ##--- #-#-- #--#- -#-#- --##- --#-# ---##
4) ##--- #-#-- #--#- -#-#- -#--# --#-# ---##
5) ##--- #-#-- #--#- #---# -#--# --#-# ---##
I'm using a breadth first search, with 5 stones, it's running within seconds, but with 10 stones, it's taking hours, the time is increasing exponentially with the depth. How can I deal with this?
My Codes:
States.java
import java.util.ArrayList;
public class State {
public int stones;
public Soldiers[] soldiers;
public String currentState ="";
public boolean visited = false;
public State(int stones,int Numsoldiers){
System.out.println(Numsoldiers);
this.stones = stones;
soldiers = new Soldiers[Numsoldiers];
System.out.println("length" + soldiers.length);
initState();
}
public State(int stones,Soldiers[] soldiers){
this.stones = stones;
this.soldiers = soldiers;
paintState();
}
public void initState(){
for(int i=0;i<soldiers.length;i++)
{
soldiers[i] = new Soldiers();
soldiers[i].position =i;
currentState+="#";
}
for(int j=soldiers.length;j<stones;j++)
{
currentState+="-";
}
}
private void paintState(){
for(int j=0;j<stones;j++)
{
currentState+="-";
}
char[] stateChar = currentState.toCharArray();
currentState = "";
for(int i=0;i<soldiers.length;i++){
stateChar[soldiers[i].position] = '#';
}
for(int k=0; k<stateChar.length;k++){
currentState += stateChar[k];
}
}
public void printState(){
System.out.println(currentState);
}
public ArrayList<State> getNextStates(){
ArrayList<State> States = new ArrayList<State>();
for(int i=0;i<soldiers.length;i++){
Soldiers[] newSoldiers = new Soldiers[soldiers.length];
for(int j=0;j<soldiers.length;j++){
newSoldiers[j] = new Soldiers(soldiers[j].position);
}
if(!((newSoldiers[i].position+1)==stones))
{
if((currentState.charAt((newSoldiers[i].position+1))=='-'))
{
newSoldiers[i].move();
States.add(new State(stones,newSoldiers));
}
}
}
if(States.size()==0)
{
TestSoldiers.count++;
}
return States;
}
}
Soldiers.java
public class Soldiers {
int position = 0;
public Soldiers(){
position =0;
}
public Soldiers(int pos){
position = pos;
}
public void move(){
position ++;
}
}
TestSoldiers.java
import java.util.LinkedList;
import java.util.Queue;
public class TestSoldiers {
public static int count=0;
public static void main(String[] args){
TestSoldiers t = new TestSoldiers();
}
public TestSoldiers()
{
State s = new State(10,3);
breadthFirstTraversal(s);
System.out.println(count);
}
public void breadthFirstTraversal(State rootNode){
Queue<State> q = new LinkedList<State>();
q.add(rootNode);
while(!q.isEmpty()){
State n = (State)q.poll();
n.printState();
for(State adj : n.getNextStates()){
q.add(adj);
}
}
}
}
How can I make it so that I will only consider each State once while maintaining the integrity of the total number of ways to end (counts in TestSoldiers.java)?
For those of you who want to modify the parameters, it's the new State(n,k) where n is the number of stones and k is the number of soldiers.
Memoization might come in handy.
The idea would be to run depth-first search to count the number of ways to get from the current state to the end, and store this result, then look up the already-calculated value if ever that state is repeated.
For instance, there are 2 ways to reach the end from -#-#-, so, storing this result when we get there via -##--, we could simply look up 2 when we get there via #--#-.
The simplest (but far from most efficient) way to store these would simply be to have a:
Map<Pair<Integer (Position1), Integer (Position2)>, Integer (Count)>
More generically, you could perhaps make that Pair a List.
A more efficient approach would be to have a bitmap where each bit corresponds to whether or not there's a soldier at some given position. So -#-#- would correspond to 01010, which could simply be stored in an int as 10 in decimal - if there are more than 64 stones (i.e. what would fit into a long), you could use a BitSet.
You might be better using combinatorics to compute the number of paths.
For example, suppose there are 2 soldiers and 5 steps.
Represent the distance the first soldier has moved by y, and the distance the second soldier has moved by x.
You are trying to count the number of monotonic paths from 0,0 to 3,3 such that y is never greater than x.
This is a well known problem and the answer is given by the Catalan numbers. In this case, the answer is given by the Catalan number for n=3, which is 5.
When you have more than 2 soldiers you will need to use multidimensional Catalan numbers. A useful guide and formula can be found on OEIS:
T(m, n) = 0! * 1! * .. * (n-1)! * (m * n)! / ( m! * (m+1)! * .. * (m+n-1)! )
My solution runs 10 positions in less than 1 second. The solution is quick and dirty, but the algorithm is what you should be interested in right?
The idea of my algorithm is:
manage a set of paths to compute. start with the path where both soldiers are at the left most positions.
if the set of paths to compute is not empty pick any path and remove it from the set.
if the path is terminated (both soldiers are at the most right positions) print the path. continue with 2.
extend the path by moving the head soldier if possible and put it into the set.
extend the path by moving the tail soldier if possible and put it into the set.
That's it.
public static void main(String[] args) {
List<Node> nodes = Node.newRootNode(10);
while (!nodes.isEmpty()) {
Node node = nodes.remove(0);
if (node.isLeaf()) node.printPath();
else {
if (node.headSoldierCanMove()) nodes.add(node.moveHeadSoldier());
if (node.tailSoldierCanMove()) nodes.add(node.moveTailSoldier());
}
}
}
static final class Node {
static List<Node> newRootNode(final int maxPos) {
return new ArrayList<Node>() {{
add(new Node(1, 2, maxPos, ""));
}};
}
private final int maxPos;
private final String path;
private int tailPos = 1;
private int headPos = tailPos + 1;
private Node(int tailPos, int headPos, int maxPos, String path) {
this.maxPos = maxPos;
this.tailPos = tailPos;
this.headPos = headPos;
this.path = addPath(path);
}
boolean tailSoldierCanMove() {
return tailPos < headPos - 1;
}
Node moveTailSoldier() {
return new Node(tailPos + 1, headPos, maxPos, path);
}
boolean headSoldierCanMove() {
return headPos < maxPos;
}
Node moveHeadSoldier() {
return new Node(tailPos, headPos + 1, maxPos, path);
}
void printPath() {
System.out.println(path);
}
boolean isLeaf() {
return headPos == maxPos && tailPos == headPos - 1;
}
private String addPath(String prefix) {
StringBuilder builder = new StringBuilder(prefix);
for (int pos = 1; pos <= maxPos; pos++) {
builder.append(tailPos == pos || headPos == pos ? "#" : "-");
}
return builder.append(" ").toString();
}
}

Depth-first search terminating early

I'm creating a program in Java that solves the n-puzzle, without using heuristics, simply just with depth-first and breadth-first searches of the state space. I'm struggling a little bit with my implementation of depth-first search. Sometimes it will solve the given puzzle, but other times it seems to give up early.
Here's my DFS class. DepthFirstSearch() is passed a PuzzleBoard, which is initially generated by shuffling a solved board (to ensure that the board is in a solvable state).
public class DepthFirst {
static HashSet<PuzzleBoard> usedStates = new HashSet<PuzzleBoard>();
public static void DepthFirstSearch(PuzzleBoard currentBoard)
{
// If the current state is the goal, stop.
if (PuzzleSolver.isGoal(currentBoard)) {
System.out.println("Solved!");
System.exit(0);
}
// If we haven't encountered the state before,
// attempt to find a solution from that point.
if (!usedStates.contains(currentBoard)) {
usedStates.add(currentBoard);
PuzzleSolver.print(currentBoard);
if (PuzzleSolver.blankCoordinates(currentBoard)[1] != 0) {
System.out.println("Moving left");
DepthFirstSearch(PuzzleSolver.moveLeft(currentBoard));
}
if (PuzzleSolver.blankCoordinates(currentBoard)[0] != PuzzleSolver.n-1) {
System.out.println("Moving down");
DepthFirstSearch(PuzzleSolver.moveDown(currentBoard));
}
if (PuzzleSolver.blankCoordinates(currentBoard)[1] != PuzzleSolver.n-1) {
System.out.println("Moving right");
DepthFirstSearch(PuzzleSolver.moveRight(currentBoard));
}
if (PuzzleSolver.blankCoordinates(currentBoard)[0] != 0) {
System.out.println("Moving up");
DepthFirstSearch(PuzzleSolver.moveUp(currentBoard));
}
return;
} else {
// Move up a level in the recursive calls
return;
}
}
}
I can assert that my moveUp(), moveLeft(), moveRight(), and moveDown() methods and logic work correctly, so the problem must lie somewhere else.
Here's my PuzzleBoard object class with the hashCode and equals methods:
static class PuzzleBoard {
short[][] state;
/**
* Default constructor for a board of size n
* #param n Size of the board
*/
public PuzzleBoard(short n) {
state = PuzzleSolver.getGoalState(n);
}
public PuzzleBoard(short n, short[][] initialState) {
state = initialState;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.deepHashCode(state);
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PuzzleBoard other = (PuzzleBoard) obj;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (state[i][j] != other.state[i][j])
return false;
}
}
return true;
}
}
As previously stated, sometimes the search works properly and finds a path to the solution, but other times it stops before it finds a solution and before it runs out of memory.
Here is a snippet of the output, beginning a few moves before the search stops searching.
...
Moving down
6 1 3
5 8 2
0 7 4
Moving right
6 1 3
5 8 2
7 0 4
Moving left
Moving right
Moving up
6 1 3
5 0 2
7 8 4
Moving left
Moving down
Moving right
Moving up
Moving up
Moving right
Moving down
Moving up
Moving down
Moving up
Moving down
Moving up
Moving down
Moving up
Moving down
...
I truncated it early for brevity, but it ends up just moving up and down dozens of times and never hits the solved state.
Can anyone shed light on what I'm doing wrong?
Edit: Here is MoveUp(). The rest of the move methods are implemented in the same way.
/**
* Move the blank space up
* #return The new state of the board after the move
*/
static PuzzleBoard moveUp(PuzzleBoard currentState) {
short[][] newState = currentState.state;
short col = blankCoordinates(currentState)[0];
short row = blankCoordinates(currentState)[1];
short targetCol = col;
short targetRow = row;
newState[targetCol][targetRow] = currentState.state[col - 1][row];
newState[targetCol - 1][targetRow] = 0;
return new PuzzleBoard(n, newState);
}
I have had many problems with hashset in the past best thing to try is not to store object in hashset but try to encode your object into string.
Here is a way to do it:-
StringBuffer encode(PuzzleBoard b) {
StringBuffer buff = new StringBuffer();
for(int i=0;i<b.n;i++) {
for(int j=0;j<b.n;j++) {
// "," is used as separator
buff.append(","+b.state[i][j]);
}
}
return buff;
}
Make two changes in the code:-
if(!usedStates.contains(encode(currentBoard))) {
usedStates.add(encode(currentBoard));
......
}
Note:- Here no need to write your own hashcode function & also no need to implement equals function as java has done it for you in StringBuffer.
I got one of the problems in your implementation:-
In th following code:-
static PuzzleBoard moveUp(PuzzleBoard currentState) {
short[][] newState = currentState.state;
short col = blankCoordinates(currentState)[0];
short row = blankCoordinates(currentState)[1];
short targetCol = col;
short targetRow = row;
newState[targetCol][targetRow] = currentState.state[col - 1][row];
newState[targetCol - 1][targetRow] = 0;
return new PuzzleBoard(n, newState);
}
Here you are using the reference of same array as newState from currentState.state so when you make changes to newState your currentState.state will also change which will affect DFS when the call returns. To prevent that you should initialize a new array. Heres what to be done:-
static PuzzleBoard moveUp(PuzzleBoard currentState) {
short[][] newState = new short[n][n];
short col = blankCoordinates(currentState)[0];
short row = blankCoordinates(currentState)[1];
short targetCol = col;
short targetRow = row;
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
newState[i][j] = currentState.state[i][j];
}
}
newState[targetCol][targetRow] = currentState.state[col - 1][row];
newState[targetCol - 1][targetRow] = 0;
return new PuzzleBoard(n, newState);
}
Do this change for all moveup,movedown....
Moreover I donot think your hashset is working properly because if it was then you would always find your new state in hashset and your program would stop. As in equals you comparing the state arrays with same reference hence will always get true. Please try and use my encode function as hash.

Java Sorting "queue" list based on DateTime and Z Position (part of school project)

For a school project i have a list of 50k containers that arrive on a boat.
These containers need to be sorted in a list in such a way that the earliest departure DateTimes are at the top and the containers above those above them.
This list then gets used for a crane that picks them up in order.
I started out with 2 Collection.sort() methods:
1st one to get them in the right X>Y>Z order
Collections.sort(containers, new Comparator<ContainerData>()
{
#Override
public int compare(ContainerData contData1, ContainerData contData2)
{
return positionSort(contData1.getLocation(),contData2.getLocation());
}
});
Then another one to reorder the dates while keeping the position in mind:
Collections.sort(containers, new Comparator<ContainerData>()
{
#Override
public int compare(ContainerData contData1, ContainerData contData2)
{
int c = contData1.getLeaveDateTimeFrom().compareTo(contData2.getLeaveDateTimeFrom());
int p = positionSort2(contData1.getLocation(), contData2.getLocation());
if(p != 0)
c = p;
return c;
}
});
But i never got this method to work..
What i got working now is rather quick and dirty and takes a long time to process (50seconds for all 50k):
First a sort on DateTime:
Collections.sort(containers, new Comparator<ContainerData>()
{
#Override
public int compare(ContainerData contData1, ContainerData contData2)
{
return contData1.getLeaveDateTimeFrom().compareTo(contData2.getLeaveDateTimeFrom());
}
});
Then a correction function that bumps top containers up:
containers = stackCorrection(containers);
private static List<ContainerData> stackCorrection(List<ContainerData> sortedContainerList)
{
for(int i = 0; i < sortedContainerList.size(); i++)
{
ContainerData current = sortedContainerList.get(i);
// 5 = Max Stack (0 index)
if(current.getLocation().getZ() < 5)
{ //Loop through possible containers above current
for(int j = 5; j > current.getLocation().getZ(); --j)
{ //Search for container above
for(int k = i + 1; k < sortedContainerList.size(); ++k)
if(sortedContainerList.get(k).getLocation().getX() == current.getLocation().getX())
{
if(sortedContainerList.get(k).getLocation().getY() == current.getLocation().getY())
{
if(sortedContainerList.get(k).getLocation().getZ() == j)
{ //Found -> move container above current
sortedContainerList.add(i, sortedContainerList.remove(k));
k = sortedContainerList.size();
i++;
}
}
}
}
}
}
return sortedContainerList;
}
I would like to implement this in a better/faster way. So any hints are appreciated. :)
I think you probably want to sort with a single Comparator that compares on all of the criteria. E.g.:
compareTo(other)
positionComparison = this.position.compareTo(other.position)
if positionComparison != 0
return positionComparison
return this.departureTime.compareTo(other.departureTime)

how to implement multithreaded Breadth-first search in java?

I've done the breadth-first search in a normal way.
now I'm trying to do it in a multithreaded way.
i have one queue which is shared between the threads.
i use synchronize(LockObject) when i remove a node from the queue ( FIFI queue )
so what I'm trying to do is that.
when i thread finds a solution all the other threads will stop immediately.
i assume you are traversing a tree for your BFS.
create a thread pool.
for each unexplored children in the node, retrieve a thread from the thread pool (perhaps using a Semaphore). mark the child node as 'explored' and explore the node's children in a BFS manner. when you have found a solution or done exploring all the nodes, release the semaphore.
^ i've never done this before so i might have missed out something.
Assuming you want to do this iteratively (see note at the bottom why there may be better closed solutions), this is not a great problem for exercising multi threading. The problem is that multithreading is great if you don't depend on previous results, but here you want the minimum amount of coins.
As you point out, a breadth first solution guarantees that once you reach the desired amount, you won't have any further solutions with less coins in a single threaded environment. However, in a multithreaded environment, once you start calculating a solution, you cannot guarantee that it will finish before some other solution. Let's imagine for the value 21: it can be a 20c coin and a 1c or four 5c coins and a 1c; if both are calculating simultaneously, you cannot guarantee that the first (and correct) solution will finish first. In practice, it is unlikely the situation will happen, but when you work with multithreading you want the solution to work in theory, because multithreads always fail in the demonstration, no matter if they should not have failed until the death heat of the universe.
Now you have 2 possible solutions: one is to introduce choke points at the beginning of each level; you don't start that level until the previous level is finished. The other is once you reach a solution continue doing all the calculations with a lower level than the current result (which means you cannot purge the others). Probably with all the synchronization needed you get better performance by going single threaded, but let's go on.
For the first solution, the natural form is to iterate increasing the level. You can use the solution provided by happymeal, with a Semaphore. An alternative is to use the new classes provided by java.
CoinSet getCoinSet(int desiredAmount) throws InterruptedException {
// Use whatever number of threads you prefer or another member of Executors.
final ExecutorService executor = Executors.newFixedThreadPool(10);
ResultContainer container = new ResultContainer();
container.getNext().add(new Producer(desiredAmount, new CoinSet(), container));
while (container.getResult() == null) {
executor.invokeAll(container.setNext(new Vector<Producer>()));
}
return container.getResult();
}
public class Producer implements Callable<CoinSet> {
private final int desiredAmount;
private final CoinSet data;
private final ResultContainer container;
public Producer(int desiredAmount, CoinSet data, ResultContainer container) {
this.desiredAmount = desiredAmount;
this.data = data;
this.container = container;
}
public CoinSet call() {
if (data.getSum() == desiredAmount) {
container.setResult(data);
return data;
} else {
Collection<CoinSet> nextSets = data.addCoins();
for (CoinSet nextSet : nextSets) {
container.getNext().add(new Producer(desiredAmount, nextSet, container));
}
return null;
}
}
}
// Probably it is better to split this class, but you then need to pass too many parameters
// The only really needed part is to create a wrapper around getNext, since invokeAll is
// undefined if you modify the list of tasks.
public class ResultContainer {
// I use Vector because it is synchronized.
private Vector<Producer> next = new Vector<Producer>();
private CoinSet result = null;
// Note I return the existing value.
public Vector<Producer> setNext(Vector<Producer> newValue) {
Vector<Producer> current = next;
next = newValue;
return current;
}
public Vector<Producer> getNext() {
return next;
}
public synchronized void setResult(CoinSet newValue) {
result = newValue;
}
public synchronized CoinSet getResult() {
return result;
}
}
This still has the problem that existing tasks are executed; however, it is simple to fix that; pass the thread executor into each Producer (or the container). Then, when you find a result, call executor.shutdownNow. The threads that are executing won't be interrupted, but the operation in each thread is trivial so it will finish fast; the runnables that have not started won't start.
The second option means you have to let all the current tasks finish, unless you keep track of how many tasks you have run at each level. You no longer need to keep track of the levels, though, and you don't need the while cycle. Instead, you just call
executor.submit(new Producer(new CoinSet(), desiredAmount, container)).get();
And then, the call method is pretty similar (assume you have executor in the Producer):
public CoinSet call() {
if (container.getResult() != null && data.getCount() < container.getResult().getCount()) {
if (data.getSum() == desiredAmount)) {
container.setResult(data);
return data;
} else {
Collection<CoinSet> nextSets = data.addCoins();
for (CoinSet nextSet : nextSets) {
executor.submit(new Producer(desiredAmount, nextSet, container));
}
return null;
}
}
}
and you also have to modify container.setResult, since you cannot depend that between the if and setting the value it has not been set by some other threads (threads are really annoying, aren't they?)
public synchronized void setResult(CoinSet newValue) {
if (newValue.getCount() < result.getCount()) {
result = newValue;
}
}
In all previous answers, CoinSet.getSum() returns the sum of the coins in the set, CoinSet.getCount() returns the number of coins, and CoinSet.addCoins() returns a Collection of CoinSet in which each element is the current CoinSet plus one coin of each possible different value
Note: For the problem of the coins with the values 1, 5, 10 and 20, the simplest solution is take the amount and divide it by the largest coin. Then take the modulus of that and use the next largest value and so on. That is the minimum amount of coins you are going to need. This rule applies (AFAICT) when the following property if true: if for all consecutive pairs of coin values (i.e. in this case, 1-5, 5-10, 10-20) you can reach any int multiple of the lower element in the pair with with a smaller number of coins using the larger element and whatever coins are necessary. You only need to prove it to the min common multiple of both elements in the pair (after that it repeats itself)
I gather from your comment on happymeal's anwer that you are trying to find how to reach a specific amount of money by adding coins of 1c, 5c, 10c and 20c.
Since each coin denomination divides the denomination of the next bigger coin, this can be solved in constant time as follows:
int[] coinCount(int amount) {
int[] coinValue = {20, 10, 5, 1};
int[] coinCount = new int[coinValue.length];
for (int i = 0; i < coinValue.length; i++) {
coinCount[i] = amount / coinValue[i];
amount -= coinCount[i] * coinValue[i];
}
return coinCount;
}
Take home message: Try to optimize your algorithm before resorting to multithreading, because algorithmic improvements can yield much greater improvements.
I've successfully implemented it.
what i did is that i took all the nodes in the first level, let's say 4 nodes.
then i had 2 threads. each one takes 2 nodes and generate their children. whenever a node finds a solution it has to report the level that it found the solution in and limit the searching level so other threads don't exceed the level.
only the reporting method should be synchronized.
i did the code for the coins change problem. this is my code for others to use
Main Class (CoinsProblemBFS.java)
package coinsproblembfs;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Scanner;
/**
*
* #author Kassem M. Bagher
*/
public class CoinsProblemBFS
{
private static List<Item> MoneyList = new ArrayList<Item>();
private static Queue<Item> q = new LinkedList<Item>();
private static LinkedList<Item> tmpQ;
public static Object lockLevelLimitation = new Object();
public static int searchLevelLimit = 1000;
public static Item lastFoundNode = null;
private static int numberOfThreads = 2;
private static void InitializeQueu(Item Root)
{
for (int x = 0; x < MoneyList.size(); x++)
{
Item t = new Item();
t.value = MoneyList.get(x).value;
t.Totalvalue = MoneyList.get(x).Totalvalue;
t.Title = MoneyList.get(x).Title;
t.parent = Root;
t.level = 1;
q.add(t);
}
}
private static int[] calculateQueueLimit(int numberOfItems, int numberOfThreads)
{
int total = 0;
int[] queueLimit = new int[numberOfThreads];
for (int x = 0; x < numberOfItems; x++)
{
if (total < numberOfItems)
{
queueLimit[x % numberOfThreads] += 1;
total++;
}
else
{
break;
}
}
return queueLimit;
}
private static void initializeMoneyList(int numberOfItems, Item Root)
{
for (int x = 0; x < numberOfItems; x++)
{
Scanner input = new Scanner(System.in);
Item t = new Item();
System.out.print("Enter the Title and Value for item " + (x + 1) + ": ");
String tmp = input.nextLine();
t.Title = tmp.split(" ")[0];
t.value = Double.parseDouble(tmp.split(" ")[1]);
t.Totalvalue = t.value;
t.parent = Root;
MoneyList.add(t);
}
}
private static void printPath(Item item)
{
System.out.println("\nSolution Found in Thread:" + item.winnerThreadName + "\nExecution Time: " + item.searchTime + " ms, " + (item.searchTime / 1000) + " s");
while (item != null)
{
for (Item listItem : MoneyList)
{
if (listItem.Title.equals(item.Title))
{
listItem.counter++;
}
}
item = item.parent;
}
for (Item listItem : MoneyList)
{
System.out.println(listItem.Title + " x " + listItem.counter);
}
}
public static void main(String[] args) throws InterruptedException
{
Item Root = new Item();
Root.Title = "Root Node";
Scanner input = new Scanner(System.in);
System.out.print("Number of Items: ");
int numberOfItems = input.nextInt();
input.nextLine();
initializeMoneyList(numberOfItems, Root);
System.out.print("Enter the Amount of Money: ");
double searchValue = input.nextDouble();
int searchLimit = (int) Math.ceil((searchValue / MoneyList.get(MoneyList.size() - 1).value));
System.out.print("Number of Threads (Muste be less than the number of items): ");
numberOfThreads = input.nextInt();
if (numberOfThreads > numberOfItems)
{
System.exit(1);
}
InitializeQueu(Root);
int[] queueLimit = calculateQueueLimit(numberOfItems, numberOfThreads);
List<Thread> threadList = new ArrayList<Thread>();
for (int x = 0; x < numberOfThreads; x++)
{
tmpQ = new LinkedList<Item>();
for (int y = 0; y < queueLimit[x]; y++)
{
tmpQ.add(q.remove());
}
BFS tmpThreadObject = new BFS(MoneyList, searchValue, tmpQ);
Thread t = new Thread(tmpThreadObject);
t.setName((x + 1) + "");
threadList.add(t);
}
for (Thread t : threadList)
{
t.start();
}
boolean finish = false;
while (!finish)
{
Thread.sleep(250);
for (Thread t : threadList)
{
if (t.isAlive())
{
finish = false;
break;
}
else
{
finish = true;
}
}
}
printPath(lastFoundNode);
}
}
Item Class (Item.java)
package coinsproblembfs;
/**
*
* #author Kassem
*/
public class Item
{
String Title = "";
double value = 0;
int level = 0;
double Totalvalue = 0;
int counter = 0;
Item parent = null;
long searchTime = 0;
String winnerThreadName="";
}
Threads Class (BFS.java)
package coinsproblembfs;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
*
* #author Kassem M. Bagher
*/
public class BFS implements Runnable
{
private LinkedList<Item> q;
private List<Item> MoneyList;
private double searchValue = 0;
private long start = 0, end = 0;
public BFS(List<Item> monyList, double searchValue, LinkedList<Item> queue)
{
q = new LinkedList<Item>();
MoneyList = new ArrayList<Item>();
this.searchValue = searchValue;
for (int x = 0; x < queue.size(); x++)
{
q.addLast(queue.get(x));
}
for (int x = 0; x < monyList.size(); x++)
{
MoneyList.add(monyList.get(x));
}
}
private synchronized void printPath(Item item)
{
while (item != null)
{
for (Item listItem : MoneyList)
{
if (listItem.Title.equals(item.Title))
{
listItem.counter++;
}
}
item = item.parent;
}
for (Item listItem : MoneyList)
{
System.out.println(listItem.Title + " x " + listItem.counter);
}
}
private void addChildren(Item node, LinkedList<Item> q, boolean initialized)
{
for (int x = 0; x < MoneyList.size(); x++)
{
Item t = new Item();
t.value = MoneyList.get(x).value;
if (initialized)
{
t.Totalvalue = 0;
t.level = 0;
}
else
{
t.parent = node;
t.Totalvalue = MoneyList.get(x).Totalvalue;
if (t.parent == null)
{
t.level = 0;
}
else
{
t.level = t.parent.level + 1;
}
}
t.Title = MoneyList.get(x).Title;
q.addLast(t);
}
}
#Override
public void run()
{
start = System.currentTimeMillis();
try
{
while (!q.isEmpty())
{
Item node = null;
node = (Item) q.removeFirst();
node.Totalvalue = node.value + node.parent.Totalvalue;
if (node.level < CoinsProblemBFS.searchLevelLimit)
{
if (node.Totalvalue == searchValue)
{
synchronized (CoinsProblemBFS.lockLevelLimitation)
{
CoinsProblemBFS.searchLevelLimit = node.level;
CoinsProblemBFS.lastFoundNode = node;
end = System.currentTimeMillis();
CoinsProblemBFS.lastFoundNode.searchTime = (end - start);
CoinsProblemBFS.lastFoundNode.winnerThreadName=Thread.currentThread().getName();
}
}
else
{
if (node.level + 1 < CoinsProblemBFS.searchLevelLimit)
{
addChildren(node, q, false);
}
}
}
}
} catch (Exception e)
{
e.printStackTrace();
}
}
}
Sample Input:
Number of Items: 4
Enter the Title and Value for item 1: one 1
Enter the Title and Value for item 2: five 5
Enter the Title and Value for item 3: ten 10
Enter the Title and Value for item 4: twenty 20
Enter the Amount of Money: 150
Number of Threads (Muste be less than the number of items): 2

Categories