I called it three "Ice Bucket Challenge" for fun. ;) Here is the problem description.
There are an 8-liter bucket filled with ice water and empty 3-liter and 5-liter buckets. You solve the puzzle by using the three buckets to divide the 8 liters of water into two equal parts of 4 liters. Try to solve the puzzle in the fewest number of moves.
Although to find a fewest number of moves is not easy, but I can design depth first search to find the necessary moves to distribute the waters.
Here is the code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static boolean threeBuckets(Integer[] curr, Integer[] max, List<List<Integer>> visited){ | |
//skip the ones we already try | |
if(visited.contains(Arrays.asList(curr))) | |
return false; | |
visited.add(Arrays.asList(curr)); | |
if(isDone(curr)){ | |
//print out the solution | |
System.out.println(visited); | |
return true; | |
} | |
for(int i = 0; i<3; i++){ | |
if(curr[i]>0){ | |
//transfer water to other buckets | |
for(int j = 0; j<3; j++){ | |
//skip itself and the bucket is already full | |
if(j==i || curr[j] == max[j]) | |
continue; | |
//we are going to dump as much water as we can | |
//make a copy of the buckets so we can retry later on | |
Integer[] copy = Arrays.copyOf(curr, 3); | |
if(copy[i] + copy[j] <= max[j]){ | |
copy[j] = copy[i] + copy[j]; | |
copy[i] = 0; | |
}else{ | |
int t = copy[i] + copy[j]; | |
copy[j] = max[j]; | |
copy[i] = t - copy[j]; | |
} | |
if(threeBuckets(copy, max, visited)) | |
return true; | |
} | |
} | |
} | |
return false; | |
} | |
private static boolean isDone(Integer[] curr){ | |
return curr[0] == 4 || curr[1] == 4 || curr[2] == 4; | |
} |
The idea here is to for each possible case, we find the all possible cases which can be derived from it. For example, from 8, 0, 0, it could be 5, 0, 3 or 3, 5, 0. And we use a list keep track of the cases we already visited. Think of all possible cases as a graph, we essentially do a depth first search until we find the case contains 4. A potential solution to find the fewest moves is to use the breath first search. We can use a Queue to contain the list of cases we already visited, then generate the queue of next level based on that, also keep track of the parent case for each case in the queue until we find the case.
It's also called waterjug problem, a classical AI problem. One thing we need to know is that it is necessary to calculate gcd of 3 numbers to see if it is divisible by 4 to ensure it has an answer.
ReplyDeletegcd(3,5,8) is 1 is not divisible by 4. i guess you mean the other way around.
DeleteCorrect
Delete