Outputs 2147483647 as a distance in final answer in Dijkstra - java

The user will be asked what path and what distance. Then it'll compute the shortest distance using Dijkstra's algorithm. The problem is some distance and paths are wrong. There are distances that has 2147483647 and its path is null. The algo works perfectly with zero as a starting point. How do i fix it?
If the user inputs
Enter first path: 0
Enter second path: 1
Enter distance: 1
Do you want to add path again? y
Enter first path: 1
Enter second path: 3
Enter distance: 2
Do you want to add path again? y
Enter first path: 3
Enter second path: 5
Enter distance: 4
Do you want to add path again? y
Enter first path: 1
Enter second path: 2
Enter distance: 3
Do you want to add path again? y
Enter first path: 0
Enter second path: 2
Enter distance: 8
Do you want to add path again? y
Enter first path: 0
Enter second path: 4
Enter distance: 9
Do you want to add path again? n
V D P
0 2147483647null //this part should be 1 and the path is 1-0
1 0null
2 31 - 2
3 21 - 3
4 2147483647null // this part should be 10 and the path is 0-4
5 63 - 5
=========================================================================
import java.util.*;
public class DijkstraAlgo {
final static int VERTICES = 6;
public static int minDistance(int distance[], Boolean shortestPath[]){
int minDist = Integer.MAX_VALUE;
int minIndex = -1;
for(int i = 0;i < VERTICES;i++){
if(shortestPath[i] == false && distance[i] <= minDist){
minDist = distance[i];
minIndex = i;
}
}
return minIndex;
}
public static void dijkstra(int path[][], int startingPoint){
int shortestDist[] = new int[VERTICES];
Boolean shortestPath[] = new Boolean[VERTICES];
String paths[] = new String[VERTICES];
for(int i = 0;i < VERTICES;i++){
shortestDist[i] = Integer.MAX_VALUE;
shortestPath[i] = false;
}
shortestDist[startingPoint] = 0;
for(int ctr = 0;ctr < VERTICES - 1;ctr++){
int index = minDistance(shortestDist, shortestPath);
shortestPath[index] = true;
for(int j = 0;j < VERTICES;j++){
if(!shortestPath[j] && path[index][j] != 0 && shortestDist[index] != Integer.MAX_VALUE && shortestDist[index] + path[index][j] < shortestDist[j]){
shortestDist[j] = shortestDist[index] + path[index][j];
paths[j] = Integer.toString(index) + " - " + " " + Integer.toString(j);
System.out.println(shortestDist[j]);
}
}
}
printAnswer(shortestDist, VERTICES, paths);
}
public static void printAnswer(int distance[], int vertices, String paths[]){
System.out.println("V D P");
for(int i = 0; i < VERTICES; i++)
System.out.println(i + " " + distance[i] + paths[i]);
}
public static void main(String args[]){
int start;
int end;
int path[][] = new int[6][6];
int distance;
Scanner input = new Scanner(System.in);
String choose;
boolean ans = true;
while(ans == true){
System.out.print("Enter first path: ");
start = input.nextInt();
System.out.print("Enter second path: ");
end = input.nextInt();
System.out.print("Enter distance: ");
distance = input.nextInt();
path[start][end] = distance;
System.out.print("Do you want to add path again? ");
choose = input.next();
if(choose.equals("y") || choose.equals("Y"))
ans = true;
else if(choose.equals("n") || choose.equals("N"))
ans = false;
else
System.out.println("Invalid input!");
}
dijkstra(path, 1);
}
}

I don't know what's wrong with your code, being honest. I don't plan to go through and try to debug it either; Eclipse can do that for you (as I linked in the comment).
What I will provide is a better means of approaching this, IMO. Storing your data in arrays of integers is a convoluted approach that's going to lead to confusion (as is evident here). One of the main benefits of using an object-oriented language like Java is that you can form your data in a coherent manner relevant to the context.
Consider creating two classes:
public class DijkstraNode {
private int label;
private List<DijkstraLink> links;
public DijkstraNode(int label) {
this.label = label;
links = new ArrayList<DijkstraLink>();
}
public int getLabel() {
return label;
}
public void addLink(DijkstraLink link) {
links.add(link);
}
public List<DijkstraLink> getLinks() {
return links;
}
}
...
public class DijkstraLink {
private DijkstraNode node;
private int distance;
public DijkstraLink(DijkstraNode node, int distance) {
this.node = node;
this.distance = distance;
}
public DijkstraNode getLinkedNode() {
return node;
}
public int getDistance() {
return distance;
}
}
Whenever you create a bi-directional link between nodes:
public void createTwoWayLink(DijkstraNode first, DijkstraNode second, int distance) {
first.addLink(new DijkstraLink(second, distance));
second.addLink(new DijkstraLink(first, distance));
}
Then evaluating Dijkstra's becomes a much simplier task:
public void computeDijkstras(DijkstraNode startNode, List<DijkstraNode> nodes) {
Map<DijkstraNode, Integer> distances = new HashMap<DijkstraNode, Integer>();
for (DijkstraNode node : nodes) {
if (node != startNode) {
distances.put(node, Integer.MAX_VALUE);
}
else {
distances.put(node, 0);
}
}
List<DijkstraNode> computedNodes = new ArrayList<DijkstraNode>();
DijkstraNode toEval = computeSmallestUncomputedNode(distances, computedNodes); // TODO
while (toEval != null) {
for (DijkstraLink link : toEval.getLinks()) {
if (computedNodes.contains(link.getLinkedNode()) {
continue;
}
int evalDist = link.getDistance() + distances.get(toEval);
if (evalDist < distances.get(link.getLinkedNode())) {
distances.put(link.getLinkedNode(), evalDist);
}
}
computedNodes.add(toEval);
toEval = computeSmallestUncomputedNode(distances, computedNodes);
}
// distances computed; do whatever.
}
This isn't a complete implementation. I didn't want to do your homework for you. However, I did want to include enough of an example of how capitalizing on object-oriented design and internal Java data structures (such as the List and Map objects used) make execution much more coherent, and, thus, easier to work with. Hope this helps.

Related

Algorithm to find `balanced number` - the same number of even and odd dividers

We define balanced number as number which has the same number of even and odd dividers e.g (2 and 6 are balanced numbers). I tried to do task for polish SPOJ however I always exceed time.
The task is to find the smallest balance number bigger than given on input.
There is example input:
2 (amount of data set)
1
2
and output should be:
2
6
This is my code:
import java.math.BigDecimal;
import java.util.Scanner;
public class Main {
private static final BigDecimal TWO = new BigDecimal("2");
public static void main(String[] args) throws java.lang.Exception {
Scanner in = new Scanner(System.in);
int numberOfAttempts = in.nextInt();
for (int i = 0; i < numberOfAttempts; i++) {
BigDecimal fromNumber = in.nextBigDecimal();
findBalancedNumber(fromNumber);
}
}
private static boolean isEven(BigDecimal number){
if(number.remainder(new BigDecimal("2")).compareTo(BigDecimal.ZERO) != 0){
return false;
}
return true;
}
private static void findBalancedNumber(BigDecimal fromNumber) {
BigDecimal potentialBalancedNumber = fromNumber.add(BigDecimal.ONE);
while (true) {
int evenDivider = 0;
int oddDivider = 1; //to not start from 1 as divisor, it's always odd and divide potentialBalancedNumber so can start checking divisors from 2
if (isEven(potentialBalancedNumber)) {
evenDivider = 1;
} else {
oddDivider++;
}
for (BigDecimal divider = TWO; (divider.compareTo(potentialBalancedNumber.divide(TWO)) == -1 || divider.compareTo(potentialBalancedNumber.divide(TWO)) == 0); divider = divider.add(BigDecimal.ONE)) {
boolean isDivisor = potentialBalancedNumber.remainder(divider).compareTo(BigDecimal.ZERO) == 0;
if(isDivisor){
boolean isEven = divider.remainder(new BigDecimal("2")).compareTo(BigDecimal.ZERO) == 0;
boolean isOdd = divider.remainder(new BigDecimal("2")).compareTo(BigDecimal.ZERO) != 0;
if (isDivisor && isEven) {
evenDivider++;
} else if (isDivisor && isOdd) {
oddDivider++;
}
}
}
if (oddDivider == evenDivider) { //found balanced number
System.out.println(potentialBalancedNumber);
break;
}
potentialBalancedNumber = potentialBalancedNumber.add(BigDecimal.ONE);
}
}
}
It seems to work fine but is too slow. Can you please help to find way to optimize it, am I missing something?
As #MarkDickinson suggested, answer is:
private static void findBalancedNumberOptimized(BigDecimal fromNumber) { //2,6,10,14,18,22,26...
if(fromNumber.compareTo(BigDecimal.ONE) == 0){
System.out.println(2);
}
else {
BigDecimal result = fromNumber.divide(new BigDecimal("4")).setScale(0, RoundingMode.HALF_UP).add(BigDecimal.ONE);
result = (TWO.multiply(result).subtract(BigDecimal.ONE)).multiply(TWO); //2(2n-1)
System.out.println(result);
}
}
and it's finally green, thanks Mark!

Staircase problem: How to print the combinations?

Question:
In this problem, the scenario we are evaluating is the following: You're standing at the base of a staircase and are heading to the top. A small stride will move up one stair, and a large stride advances two. You want to count the number of ways to climb the entire staircase based on different combinations of large and small strides. For example, a staircase of three steps can be climbed in three different ways: three small strides, one small stride followed by one large stride, or one large followed by one small.
The call of waysToClimb(3) should produce the following output:
1 1 1,
1 2,
2 1
My code:
public static void waysToClimb(int n){
if(n == 0)
System.out.print("");
else if(n == 1)
System.out.print("1");
else {
System.out.print("1 ");
waysToClimb(n - 1);
System.out.print(",");
System.out.print("2 ");
waysToClimb(n - 2);
}
}
My output:
1 1 1,
2,
2 1
My recursion doesn't seem to remember the path it took any idea how to fix it?
Edit:
Thank you guys for the responses. Sorry for the late reply
I figured it out
public static void waysToClimb(int n){
String s ="[";
int p=0;
com(s,p,n);
}
public static void com(String s,int p,int n){
if(n==0 && p==2)
System.out.print(s.substring(0,s.length()-2)+"]");
else if(n==0 && p !=0)
System.out.print(s+"");
else if(n==0 && p==0)
System.out.print("");
else if(n==1)
System.out.print(s+"1]");
else {
com(s+"1, ",1,n-1);
System.out.println();
com(s+"2, ",2,n-2);
}
}
If you explicity want to print all paths (different than counting them or finding a specific one), you need to store them all the way down to 0.
public static void waysToClimb(int n, List<Integer> path)
{
if (n == 0)
{
// print whole path
for (Integer i: path)
{
System.out.print(i + " ");
}
System.out.println();
}
else if (n == 1)
{
List<Integer> newPath = new ArrayList<Integer>(path);
newPath.add(1);
waysToClimb(n-1, newPath);
}
else if (n > 1)
{
List<Integer> newPath1 = new ArrayList<Integer>(path);
newPath1.add(1);
waysToClimb(n-1, newPath1);
List<Integer> newPath2 = new ArrayList<Integer>(path);
newPath2.add(2);
waysToClimb(n-2, newPath2);
}
}
initial call: waysToClimb(5, new ArrayList<Integer>());
Below mentioned solution will work similar to Depth First Search, it will explore one path. Once a path is completed, it will backtrace and explore other paths:
public class Demo {
private static LinkedList<Integer> ll = new LinkedList<Integer>(){{ add(1);add(2);}};
public static void main(String args[]) {
waysToClimb(4, "");
}
public static void waysToClimb(int n, String res) {
if (ll.peek() > n)
System.out.println(res);
else {
for (Integer elem : ll) {
if(n-elem >= 0)
waysToClimb(n - elem, res + String.valueOf(elem) + " ");
}
}
}
}
public class Test2 {
public int climbStairs(int n) {
// List of lists to store all the combinations
List<List<Integer>> ans = new ArrayList<List<Integer>>();
// initially, sending in an empty list that will store the first combination
csHelper(n, new ArrayList<Integer>(), ans);
// a helper method to print list of lists
print2dList(ans);
return ans.size();
}
private void csHelper(int n, List<Integer> l, List<List<Integer>> ans) {
// if there are no more stairs to climb, add the current combination to ans list
if(n == 0) {
ans.add(new ArrayList<Integer>(l));
}
// a necessary check that prevent user at (n-1)th stair to climb using 2 stairs
if(n < 0) {
return;
}
int currStep = 0;
// i varies from 1 to 2 as we have 2 choices i.e. to either climb using 1 or 2 steps
for(int i = 1; i <= 2; i++) {
// climbing using step 1 when i = 1 and using 2 when i = 2
currStep += 1;
// adding current step to the arraylist(check parameter of this method)
l.add(currStep);
// make a recursive call with less number of stairs left to climb
csHelper(n - currStep, l, ans);
l.remove(l.size() - 1);
}
}
private void print2dList(List<List<Integer>> ans) {
for (int i = 0; i < ans.size(); i++) {
for (int j = 0; j < ans.get(i).size(); j++) {
System.out.print(ans.get(i).get(j) + " ");
}
System.out.println();
}
}
public static void main(String[] args) {
Test2 t = new Test2();
t.climbStairs(3);
}
}
Please note this solution will timeout for larger inputs as this isn't a memoized recursive solution and can throw MLE(as I create a new list when a combination is found).
Hope this helps.
if anyone looking for a python solution, for this problem.
def way_to_climb(n, path=None, val=None):
path = [] if path is None else path
val = [] if val is None else val
if n==0:
val.append(path)
elif n==1:
new_path = path.copy()
new_path.append(1)
way_to_climb(n-1, new_path, val)
elif n>1:
new_path1 = path.copy()
new_path1.append(1)
way_to_climb(n-1, new_path1, val)
new_path2 = path.copy()
new_path2.append(2)
way_to_climb(n-2, new_path2, val)
return val
Note: it is based on the #unlut solution, here OP has used a top-down recursive approach. This solution is for all people who looking for all combination of staircase problem in python, no python question for this so i have added a python solution here
if we use a bottom-up approach and use memorization, then we can solve the problem faster.
Even though you did find the correct answer to the problem with your code, you can still improve upon it by using just one if to check if the steps left is 0. I used a switch to check the amount of steps taken because there are only 3 options, 0, 1, or 2. I also renamed the variables that were used to make the code more understandable to anyone seeing it for the first time, as it is quite confusing if you are just using one letter variable names. Even with all these changes the codes run the same, I just thought it might be better to add some of these things for others who might view this question in the future.
public static void climbStairsHelper(String pathStr, int stepsTaken, int stepsLeft)
{
if(stepsLeft == 0)
{
switch(stepsTaken)
{
case 2:
System.out.print(pathStr.substring(0, pathStr.length() - 2) + "]");
break;
case 1:
System.out.print(pathStr + "");
break;
case 0:
System.out.print("");
break;
}
}
else if(stepsLeft == 1)
{
System.out.print(pathStr + "1]");
}
else
{
climbStairsHelper(pathStr + "1, ", 1, stepsLeft - 1);
System.out.println();
climbStairsHelper(pathStr + "2, ", 2, stepsLeft - 2);
}
}`
`

Runtime error in java code

I'm creating a program for an assignment which takes an input from System.in in the following format:
Inky Pinky Blinky Clyde Luigi Mario Bowser
0 2
1 2
5 6
3 5
2 4
4 5
2 3
1 4
closefriends 1 2 4
where the first line is persons, the numbers are friendships.
The program checks whether or not the people listed in the last line are in a "close friendship", where they're all friends.
I represent the network as an incident matrix, and it passes every test on the test site we use, except one, which fails with a "Runtime Error". I know it's not an exception, because catching all exceptions does nothing to the error, while catching all errors does.
Here's the code:
public class CloseFriends {
// Contains edges represented as an incident matrix
private static boolean edges[][];
// Adds a directed edge between v1 and v2
// The method sorts the edges to reduce space used
public static void addEdge(int v1, int v2) {
if (v1 > v2) {
edges[v1][v2] = true;
}
else {
edges[v2][v1] = true;
}
}
// Creates a graph with V vertices
public static void createVertices(int V) {
edges = new boolean[V][V];
}
// Checks if an edge exists between v1 and v2
public static boolean isFriends(int v1, int v2) {
if (v1 > v2) {
return edges[v1][v2];
}
else {
return edges[v2][v1];
}
}
// Checks if an ArrayList of vertices is close friends
public static void closeFriends(ArrayList<Integer> vertices) {
int count = 0;
int size = vertices.size();
for (int i = 0; i < size; i++) {
for (int j = i + 1; j < size; j++) {
if (isFriends(vertices.get(i), vertices.get(j))) {
count++;
}
}
}
// The clique should contain n*(n-1)/2 edges for everyone to be connected
if (count == (size * (size - 1) / 2)) {
System.out.println("yes");
}
else {
System.out.println("no");
}
}
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(in.readLine());
// Count vertices, and create that amount
int V = 0;
while (st.hasMoreTokens()) {
st.nextToken();
V++;
}
createVertices(V);
ArrayList<Integer> friends = new ArrayList<Integer>();
// While System.in has something to be read
while (in.ready()) {
// Read the line and add edges based on input, or run the algorithm
String edge = "";
edge = in.readLine();
if (edge != null) {
st = new StringTokenizer(edge);
if (!edge.startsWith("closefriends")) {
addEdge(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()));
}
else {
st.nextToken();
while (st.hasMoreTokens()) {
friends.add(Integer.parseInt(st.nextToken()));
}
}
}
}
closeFriends(friends);
}
}
Thanks!

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();
}
}

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