When is recursive backtracking appropriate? - java

I'm making a SudokuSolver for a class, and I'm having trouble with the solve method. My current solution uses recursive backtracking (I think).
Assignment Requirements
int solve() -- tries to solve the puzzle using the strategy described above. Returns the number of solutions.
(The strategy described above)
When assigning a number to a spot, never assign a number that, at that moment, conflicts with the spot's row, column, or square. We are up-front careful about assigning legal numbers to a spot, rather than assigning any number 1..9 and finding the problem later in the recursion. Assume that the initial grid is all legal, and make only legal spot assignments thereafter.
Pseudocode Idea
I can follow this iteratively for a small input. For example, say I have to unsolved cells Cell #1 and Cell #2. #1 has possibilities { 1, 3 } and #2 has possibilities { 2, 3 }. I would then
set 1 to 1
set 2 to 2
hasConflicts? 0 : 1
set 2 to 3
hasConflicts? 0 : 1
set 1 to 3
set 2 to 2
hasConflicts? 0 : 1
set 2 to 3
hasConflicts? 0 : 1
Actual Code
public int solve() {
long startTime = System.currentTimeMillis();
int result = 0;
if (!hasConflicts()) {
Queue<VariableCell> unsolved = getUnsolved();
reduceUnsolvedPossibilities(unsolved); // Gets the possibilities down from all of 1-9
if (!hasConflicts()) {
result = solveRec(unsolved);
}
}
mElapsedTime = System.currentTimeMillis() - startTime;
return result;
}
protected int solveRec(Queue<VariableCell> unsolved) {
if (unsolved.isEmpty()) {
return (hasConflicts()) ? 0 : 1;
}
int result = 0;
VariableCell cell = unsolved.remove();
Iterator<String> possibilityIt = cell.getPossibilities().iterator();
while (possibilityIt.hasNext()) {
cell.setSymbol(possibilityIt.next());
if (hasConflicts()) {
possibilityIt.remove();
} else {
++result;
}
}
return result + solveRec(unsolved);
}
Test Results
testSolveSingleSolution
expected 1, actual 1
testSolveSolved
expected 1, actual 1
testSolveUnsolvable
expected 0, actual 0
testSolveMultiSolutions
expected 2, actual 7 // MAJOR PROBLEM!
Some Good Explanations of Recursive Backtracking
This answer to StackOverflow - Recursive solution to Sudoku generator
This answer to StackOverflow - BackTracking in a maze
This answer to StackOverflow - Backtracking algorithm for prime sequence
This answer to StackOverflow - How to find the first solution only with this backtracking
The Wikipedia article on Backtracking
Recursive Backtracking Explanation
Question
I've done recursive backtracking before, I've looked at all those links above and more, and I'm still having trouble. I think the problem lies in my thinking about how to solve this. (See Pseudocode Idea.) Is it appropriate to use recursive backtracking for an exhaustive search? Is the backtracking right but the implementation wrong? Is there a better algorithm I can use than recursive backtracking?

This looks like an implementation problem. Check the block where you're incrementing result. Do you really want to increment for each valid value of that cell? And for that matter overwrite the older valid value if there are several that are valid?

Related

2 dimensional maze solver recursive function

I am trying to implement a 2 dimensional matrix as a maze. There is a starting point, an ending point (randomly chosen). And to make it little complicated, there are obstacles and agents. If the rat runs into an obstacle, it should backtrack and find the correct path. If it runs into an agent, it gets destroyed.
Here's a sample 4x4 matrix
1 7 1 1
2 1 1 0
1 0 1 0
1 1 1 9
Key: 0 is an obstacle, 2 is an agent, 7 is the starting point, 9 is the goal/ending point. 1 means that is is safe to move there.
The correct solution for this matrix would be:
0 1 1 0
0 0 1 0
0 0 1 0
0 0 1 1
But the rat is not intelligent (at least for this program) , so I am implementing a brute force algorithm, with random moves.
I have tried to implement this using a recursive function called mazeUtil().
Below is the function:
maze[][] is the randomized initial matrix that the rat moves through.
solution[][] is the solution matrix that will keep track of the moves.
(x, y) is the current position in the grid
n is the size of the matrix (it is a square matrix).
public static void mazeUtil(int maze[][], int solution[][], int x, int y, int n)
{
if(x == goal[0] && y == goal[1])
{
solution[x][y] = 1;
return;
}
int check = moveCheck(maze, x, y, n);
//moveCheck() return 0 for Obstacle, 1 for safe path, 2 for agent, 7 for starting point (also safe path), 9 for goal (safe path)
if (check == 2){
solution[x][y] = 1;
out.println("Oops! Ran into an agent!");
return;
}
else if(check == 0)
{
//What should I put here?
}
else if(check == 1 || check == 7 || check == 9)
{
solution[x][y] = 1;
Random newRandom = new Random();
int temp = newRandom.nextInt(3);
if(temp == 0){ //move up if possible? x--
if(x > 0)
mazeUtil(maze, solution, x-1, y, n);
else
mazeUtil(maze, solution, x+1, y, n);
}
else if (temp == 1){
if (x < n-1)
mazeUtil(maze, solution, x+1, y, n);
else
mazeUtil(maze, solution, x-1, y, n);
}
else if(temp == 2){
if (y < n-1)
mazeUtil(maze, solution, x, y+1, n);
else
mazeUtil(maze, solution, x,y-1, n);
}
else if (temp == 3){
if (y > 0)
mazeUtil(maze, solution, x, y-1, n);
else
mazeUtil(maze, solution, x, y+1, n);
}
}
}
I have to randomize the moves and that's why i have used random function. My function works quite well if it runs into an agent (2). I have also prevented the rat from going out of boundary. And it doesn't have any problem going through the safe path (1). But the problem is when it hits an obstacle. I'm thinking about backtracking. How do I add that into my function? Like save the last step, and do the reverse? And it is quite possible that there is no solution in the maze like this one
7 0 0 9
2 0 1 1
0 1 0 0
1 2 0 1
It would hit an obstacle if it goes right, and hit an agent if it goes down. It cannot move diagonally.
That brings me to my second question, how would I terminate my recursive function in that case.
At this point the only time it terminates is when it reaches the goal or hits an agent.
Any help would be appreciated. Thanks in advance
Well, let's imagine I need to solve the same problem by the same way you are solving it.
(I think the best solution for it is Path finding, as already mentioned in comments).
I will create
class Point{
public int x;
public int y;
}
and store coordinates in it.
I will store all points the rat visited in List<Point> path
In this solution you do not have problems with previous point (it is the last point in list)
As for algorithm termination -- you use algorithm with randoms. So you can't be sure that your rat will solve the simplest maze like
7 1 1
1 1 1
1 1 1
it is possible that rat will move from (0,0) to (1,0) and from (1,0) to (0,0) forever.
So, let's again imagine that I need to improve your algorithm instead of using good one.
I will store number of times the rat returned back from obstacle or visited the point in path list.
If this number > 4 I will command to my rat return back to the original point (point 7). And start the journey again.
If the rat need to return back, for example 10 times, the algorithm terminates.
Again, your algorithm is funny, and it should be interesting to see how the rat moves but it does not solve the problem. It will not work on big mazes.
Try to implement path finding. If you will have problems -- ask questions.
Good luck!
A quick point on style, to save some typing later: maze[][], solution[][] and n are all effectively global, and do not change between recursive calls (maze and solution are just passed as references to the same arrays, and n never changes). This is purely style, but you can write this as:
private static int[][] maze;
private static int[][] solution;
private static int n;
public static void mazeUtil(int x, int y) {
...
}
So on to your solution: the first point is I don't see how you know when you've reached the goal; your mazeUtil function does not return anything. For this kind of recursion, a general approach is for your solver function to return a boolean: true if the goal has been reached and false if not. Once you get a true, you just pass it back all the way up the call stack. Each time you get a false, you backtrack to the next solution.
So I'd suggest:
public static boolean mazeUtil(int x, int y) {
// return true if goal found, false otherwise
...
}
Next, I'm not sure what the practical difference between an agent and an obstacle is: running in to either causes you to backtrack. So I'd think that bit of code would be:
if (check == 2) {
out.println("Oops! Ran into an agent!");
return false;
}
if (check == 0)
out.println("Oops! Ran into an obstacle!");
return false;
}
Then the recursive bit: one point here is you do not ever reset the solution to 0 for failed attempts (actually, as the final algorithm will never backtrack more than a single step this is not actually that important, but it's good to illustrate the general approach). Given what we have so far, this should now be something like:
if (check == 9) {
out.println("Found the goal!");
return true;
}
if (check == 1 || check == 7) {
// add current position to solution
solution[x][y] = 1;
// generate random move within bounds
int nextX = ...
int nextY = ...
if (mazeUtil(nextX, nextY)) {
// we've found the solution, so just return up the call stack
return true;
}
// this attempt failed, so reset the solution array before returning
solution[x][y] = 0;
return false;
}
// shouldn't ever get here...
throw new IllegalStateException("moveCheck returned unexpected value: " + check);
Right, so far so good, but there's still a problem. As soon as one of the mazeUtil calls returns a value (either true or false) it will return that all the way up the calls stack. So if you happen to find the exit before an agent or an obstacle, all good, but that's quite unlikely. So instead of trying a single move when recursing, you need to try all possible moves.
WIth a supporting class Point, containing a simple x and y pair:
if (check == 1 || check == 7) {
// add current position to solution
solution[x][y] = 1;
// generate an array of all up/down/left/right points that are within bounds
// - for a random path need to randomise the order of the points
Point[] points = ...
for (Point next : points) {
if (mazeUtil(next.x, next.y)) {
// we've found the solution, so just return up the call stack
return true;
}
}
// this attempt failed, so reset the solution array before returning
solution[x][y] = 0;
return false;
}
And I think that's about as far as you can go with a totally ignorant rat! To see how this works, consider the following maze:
7 1
0 9
Starting at "7", possible moves are Down and Right.
If you try Down first, it returns false, so the only option left is
Right, so you end up on the "1".
If you try Right first, you still end up on the "1".
From the "1", possible moves are Down and Left:
If you try Down first, it returns true, which bubbles up the call stack - success!
If you try Left first, you end up on the "7", so recurse to the previous step.
And that's all that can ever happen. So using * for a return-false-backtrack, and ! for a success, any of the following are possible:
R-D!
R-L-D*-R-D!
R-L-R-L-R-L-R-L (keep going for a long, long time....) R-L-R-D!
So for a solvable maze, and a truly random generator, this will eventually solve the maze, although it could take a very long time. Something to note with this though, is it does not really backtrack that much: only ever a single step from a 2 or 0 node.
However, there's still the problem of the unsolveable maze, and I don't think that is possible given a totally ignorant rat. The reason for this is that for a brute force recursion like this, there are only two possible termination conditions:
The goal has been found.
All possible paths have been tried.
And with a totally ignorant rat, there is no way to detect the second!
Consider the following maze:
7 1 1 1
0 0 0 0
0 0 0 0
1 1 1 9
The totally ignorant rat will just wander left and right across the top row forever, and so the program will never terminate!
The solution to this is that the rat must be at least a bit intelligent, and remember where it has been (which will also make the solveable maze run quicker in most cases and backtrack along entire paths instead of only for single nodes). However, this answer is getting a bit too long already, so if you're interested in that I'll refer you to my other maze-solving answer here: Java Recursive Maze Solver problems
Oh, just two final points on Random:
You don't need to create a new Random each time - just create a
global one and call nextInt each time.
nextInt(n) returns between 0 (inclusive) and n (exclusive), so you
need nextInt(4) not nextInt(3).
Hope this all helps!
if you want to move in random, u need to know the states you've been already in them, so u will need a tree, otherwise u can keep the most left path when the rat is in multi way place.
now lets think of recursive + random. it can not be that hard. you can have a function that returns the list of points it has been in them, and get correct position as input, there is a bit of problem and the idiot rat can got back the way he already came from, so lets solve it with adding previous point as another input for our function.
every thing in place. now we wana know if the idiot rat runs into a dead path or an agent. how about making 2 exceptions for this situations and handling them in recursive function??
well, i don't think there will be any more problems on way. actually i'm temped to try it myselft. that would be fun :D
good luck with the idiot rat
I'd like to do some analysis of your algorithm design before proposing a solution.
You mention that you want to use a random walk algorithm. No problem with that it's a perfectly acceptable (though not necessarily efficient) way to look for a path. However you need to be aware that it has some implications.
In general random walk will not tell you when there is no solution. If you just keep trying paths at random you will never exhaust the search tree.
If this is unacceptable (i.e. it needs to be able to halt when there is no soltuion) then you need to keep a record of paths already attempted and randomise only those not yet attempted.
Random walk won't necessarily find the optimal solution unless there is only one solution. In other words if there are loops / multiple paths in your maze then there's no guarantee you are finding the fastest.
I can't actually see the difference between agents and obstacles in your problem. In both cases you need to backtrack and find another path. If there is a difference then you'll need to point it out.
So assuming your maze could have zero or more successful paths and you are not looking for the optimal path (in which case you really should use A* or similar), the structure of a solution should look something like:
public List<Position> findPath(Set<Position> closedSet, Position from, Position to) {
if (from.equals(to))
return List.of(to);
while (from.hasNeighboursNotIn(closedSet)) {
Position pos = from.getRandomNeighbourNotIn(closedSet);
closedSet.add(pos);
List<Position> path = findPath(closedSet, pos, to);
if (!path.isEmpty())
return List.of(pos, path);
}
closedSet.add(from);
return Collection.EMPTY_LIST;
}
This uses lots of pseudo-code (e.g. there is no List.of(item, list)) but you get the idea.

Number Guessing Game Over Intervals

I have just started my long path to becoming a better coder on CodeChef. People begin with the problems marked 'Easy' and I have done the same.
The Problem
The problem statement defines the following -:
n, where 1 <= n <= 10^9. This is the integer which Johnny is keeping secret.
k, where 1 <= k <= 10^5. For each test case or instance of the game, Johnny provides exactly k hints to Alice.
A hint is of the form op num Yes/No, where -
op is an operator from <, >, =.
num is an integer, again satisfying 1 <= num <= 10^9.
Yes or No are answers to the question: Does the relation n op num hold?
If the answer to the question is correct, Johnny has uttered a truth. Otherwise, he is lying.
Each hint is fed to the program and the program determines whether it is the truth or possibly a lie. My job is to find the minimum possible number of lies.
Now CodeChef's Editorial answer uses the concept of segment trees, which I cannot wrap my head around at all. I was wondering if there is an alternative data structure or method to solve this question, maybe a simpler one, considering it is in the 'Easy' category.
This is what I tried -:
class Solution //Represents a test case.
{
HashSet<SolutionObj> set = new HashSet<SolutionObj>(); //To prevent duplicates.
BigInteger max = new BigInteger("100000000"); //Max range.
BigInteger min = new BigInteger("1"); //Min range.
int lies = 0; //Lies counter.
void addHint(String s)
{
String[] vals = s.split(" ");
set.add(new SolutionObj(vals[0], vals[1], vals[2]));
}
void testHints()
{
for(SolutionObj obj : set)
{
//Given number is not in range. Lie.
if(obj.bg.compareTo(min) == -1 || obj.bg.compareTo(max) == 1)
{
lies++;
continue;
}
if(obj.yesno)
{
if(obj.operator.equals("<"))
{
max = new BigInteger(obj.bg.toString()); //Change max value
}
else if(obj.operator.equals(">"))
{
min = new BigInteger(obj.bg.toString()); //Change min value
}
}
else
{
//Still to think of this portion.
}
}
}
}
class SolutionObj //Represents a single hint.
{
String operator;
BigInteger bg;
boolean yesno;
SolutionObj(String op, String integer, String yesno)
{
operator = op;
bg = new BigInteger(integer);
if(yesno.toLowerCase().equals("yes"))
this.yesno = true;
else
this.yesno = false;
}
#Override
public boolean equals(Object o)
{
if(o instanceof SolutionObj)
{
SolutionObj s = (SolutionObj) o; //Make the cast
if(this.yesno == s.yesno && this.bg.equals(s.bg)
&& this.operator.equals(s.operator))
return true;
}
return false;
}
#Override
public int hashCode()
{
return this.bg.intValue();
}
}
Obviously this partial solution is incorrect, save for the range check that I have done before entering the if(obj.yesno) portion. I was thinking of updating the range according to the hints provided, but that approach has not borne fruit. How should I be approaching this problem, apart from using segment trees?
Consider the following approach, which may be easier to understand. Picture the 1d axis of integers, and place on it the k hints. Every hint can be regarded as '(' or ')' or '=' (greater than, less than or equal, respectively).
Example:
-----(---)-------(--=-----)-----------)
Now, the true value is somewhere on one of the 40 values of this axis, but actually only 8 segments are interesting to check, since anywhere inside a segment the number of true/false hints remains the same.
That means you can scan the hints according to their ordering on the axis, and maintain a counter of the true hints at that point.
In the example above it goes like this:
segment counter
-----------------------
-----( 3
--- 4
)-------( 3
-- 4
= 5 <---maximum
----- 4
)----------- 3
) 2
This algorithm only requires to sort the k hints and then scan them. It's near linear in k (O(k*log k), with no dependance on n), therefore it should have a reasonable running time.
Notes:
1) In practice the hints may have non-distinct positions, so you'll have to handle all hints of the same type on the same position together.
2) If you need to return the minimum set of lies, then you should maintain a set rather than a counter. That shouldn't have an effect on the time complexity if you use a hash set.
Calculate the number of lies if the target number = 1 (store this in a variable lies).
Let target = 1.
Sort and group the statements by their respective values.
Iterate through the statements.
Update target to the current statement group's value. Update lies according to how many of those statements would become either true or false.
Then update target to that value + 1 (Why do this? Consider when you have > 5 and < 7 - 6 may be the best value) and update lies appropriately (skip this step if the next statement group's value is this value).
Return the minimum value for lies.
Running time:
O(k) for the initial calculation.
O(k log k) for the sort.
O(k) for the iteration.
O(k log k) total.
My idea for this problem is similar to how Eyal Schneider view it. Denoting '>' as greater, '<' as less than and '=' as equals, we can sort all the 'hints' by their num and scan through all the interesting points one by one.
For each point, we keep in all the number of '<' and '=' from 0 to that point (in one array called int[]lessAndEqual), number of '>' and '=' from that point onward (in one array called int[]greaterAndEqual). We can easily see that the number of lies in a particular point i is equal to
lessAndEqual[i] + greaterAndEqual[i + 1]
We can easily fill the lessAndEqual and greaterAndEqual arrays by two scan in O(n) and sort all the hints in O(nlogn), which result the time complexity is O(nlogn)
Note: special treatment should be taken for the case when the num in hint is equals. Also notice that the range for num is 10^9, which require us to have some forms of point compression to fit the array into the memory

Reduce time complexity of a program (in Java)?

This question is quite a long shot. It could take quite long, so if you haven't the time I understand.
Let me start by explaining what I want to achieve:
Me and some friends play this math game where we get 6 random numbers out of a pool of possible numbers: 1 to 10, 25, 50, 75 and 100. 6 numbers are chosen out of these and no duplicates are allowed. Then a goal number will be chosen in the range of [100, 999]. With the 6 aforementioned numbers, we can use only basic operations (addition, subtraction, multiplication and division) to reach the goal. Only integers are allowed and not all 6 integers are required to reach the solution.
An example: We start with the numbers 4,8,6,9,25,100 and need to find 328.
A possible solution would be: ((4 x 100) - (9 x 8)) = 400 - 72 = 328. With this, I have only used 4 out of the 6 initial numbers and none of the numbers have been used twice. This is a valid solution.
We don't always find a solution on our own, that's why I figured a program would be useful. I have written a program (in Java) which has been tested a few times throughout and it had worked. It did not always give all the possible solutions, but it worked within its own limitations. Now I've tried to expand it so all the solutions would show.
On to the main problem:
The program that I am trying to execute is running incredibly long. As in, I would let it run for 15 minutes and it doesn't look like it's anywhere near completion. So I thought about it and the options are indeed quite endless. I start with 6 numbers, I compare the first with the other 5, then the second with the other 5 and so on until I've done this 6 times (and each comparison I compare with every operator, so 4 times again). Out of the original one single state of 6 numbers, I now have 5 times 6 times 4 = 120 states (with 5 numbers each). All of these have to undergo the same ritual, so it's no wonder it's taking so long.
The program is actually too big to list here, so I will upload it for those interested:
http://www.speedyshare.com/ksT43/MathGame3.jar
(Click on the MathGame3.jar title right next to download)
Here's the general rundown on what happens:
-6 integers + goal number are initialized
-I use the class StateNumbers that are acting as game states
-> in this class the remaining numbers (initially the 6 starting numbers)
are kept as well as the evaluated expressions, for printing purposes
This method is where the main operations happen:
StateNumbers stateInProcess = getStates().remove(0);
ArrayList<Integer> remainingNumbers = stateInProcess.getRemainingNumbers();
for(int j = 0; j < remainingNumbers.size(); j++){
for(int i = 0; i < remainingNumbers.size(); i++){
for(Operator op : Operator.values()){ // Looping over different operators
if(i == j) continue;
...
}
}
}
I evaluate for the first element all the possible operations with all the remaining numbers for that state. I then check with a self written equals to see if it's already in the arraylist of states (which acts as a queue, but the order is not of importance). If it's not there, then the state will be added to the list and then I do the same for the other elements. After that I discard the state and pick another out of the growing list.
The list grows in size to 80k states in 10 minutes and grows slower and slower. That's because there is an increasing amount of states to compare to when I want to add a new state. It's making me wonder if comparing with other states to prevent duplicates is such a good idea.
The completion of this program is not really that important, but I'd like to see it as a learning experience. I'm not asking anyone to write the code for me, but a friendly suggestion on what I could have handled better would be very much appreciated. This means if you have something you'd like to mention about another aspect of the program, please do. I'm unsure if this is too much to ask for on this forum as most topics handle a specific part of a program. While my question is specific as well, the causes could be many.
EDIT: I'm not trying to find the fastest single solution, but every solution. So if I find a solution, my program will not stop. It will however try to ignore doubles like:
((4+5)7) and (7(5+4)). Only one of the two is accepted because the equals method in addition and multiplication do not care about the positioning of the operands.
It would probably be easier to write this using recursion, i.e. a depth-first search, as this would simplify the bookkeeping for intermediary states.
If you want to keep a breath-first approach, make sure that the list of states supports efficient removal of the first element, i.e. use a java.util.Queue such as java.util.ArrayDeque. I mention this because the most frequently used List implementation (i.e. java.util.ArrayList) needs to copy its entire contents to remove the first element, which makes removing the first element very expensive if the list is large.
120 states (with 5 numbers each). All of these have to undergo the same ritual, so it's no wonder it's taking so long.
Actually, it is quite surprising that it would. After all, a 2GHz CPU performs 2 billion clock cycles per second. Even if checking a state were to take as many as 100 clock cycles, that would still mean 20 million states per second!
On the other hand, if I understand the rules of the game correctly, the set of candidate solutions is given by all orderings of the 6 numbers (of which there are 6! = 720), with one of 4 operators in the 5 spaces in between, and a defined evaluation order of the operators. That is, we have a total of 6! * 4^5 * 5! = 88 473 600 candidate solutions, so processing should complete in a couple of seconds.
PS: A full solution would probably not be very time-consuming to write, so if you wish, I can also postcode - I just didn't want to spoil your learning experience.
Update: I have written the code. It was harder than I thought, as the requirement to find all solutions implies that we need to print a solution without unwinding the stack. I, therefore, kept the history for each state on the heap. After testing, I wasn't quite happy with the performance (about 10 seconds), so I added memoization, i.e. each set of numbers is only processed once. With that, the runtime dropped to about 3 seconds.
As Stackoverflow doesn't have a spoiler tag, I increased the indentation so you have to scroll right to see anything :-)
package katas.countdown;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
enum Operator {
plus("+", true),
minus("-", false),
multiply("*", true),
divide("/", false);
final String sign;
final boolean commutes;
Operator(String sign, boolean commutes) {
this.sign = sign;
this.commutes = commutes;
}
int apply(int left, int right) {
switch (this) {
case plus:
return left + right;
case minus:
return left - right;
case multiply:
return left * right;
case divide:
int mod = left % right;
if (mod == 0) {
return left / right;
} else {
throw new ArithmeticException();
}
}
throw new AssertionError(this);
}
#Override
public String toString() {
return sign;
}
}
class Expression implements Comparable<Expression> {
final int value;
Expression(int value) {
this.value = value;
}
#Override
public int compareTo(Expression o) {
return value - o.value;
}
#Override
public int hashCode() {
return value;
}
#Override
public boolean equals(Object obj) {
return value == ((Expression) obj).value;
}
#Override
public String toString() {
return Integer.toString(value);
}
}
class OperationExpression extends Expression {
final Expression left;
final Operator operator;
final Expression right;
OperationExpression(Expression left, Operator operator, Expression right) {
super(operator.apply(left.value, right.value));
this.left = left;
this.operator = operator;
this.right = right;
}
#Override
public String toString() {
return "(" + left + " " + operator + " " + right + ")";
}
}
class State {
final Expression[] expressions;
State(int... numbers) {
expressions = new Expression[numbers.length];
for (int i = 0; i < numbers.length; i++) {
expressions[i] = new Expression(numbers[i]);
}
}
private State(Expression[] expressions) {
this.expressions = expressions;
}
/**
* #return a new state constructed by removing indices i and j, and adding expr instead
*/
State replace(int i, int j, Expression expr) {
Expression[] exprs = Arrays.copyOf(expressions, expressions.length - 1);
if (i < exprs.length) {
exprs[i] = expr;
if (j < exprs.length) {
exprs[j] = expressions[exprs.length];
}
} else {
exprs[j] = expr;
}
Arrays.sort(exprs);
return new State(exprs);
}
#Override
public boolean equals(Object obj) {
return Arrays.equals(expressions, ((State) obj).expressions);
}
public int hashCode() {
return Arrays.hashCode(expressions);
}
}
public class Solver {
final int goal;
Set<State> visited = new HashSet<>();
public Solver(int goal) {
this.goal = goal;
}
public void solve(State s) {
if (s.expressions.length > 1 && !visited.contains(s)) {
visited.add(s);
for (int i = 0; i < s.expressions.length; i++) {
for (int j = 0; j < s.expressions.length; j++) {
if (i != j) {
Expression left = s.expressions[i];
Expression right = s.expressions[j];
for (Operator op : Operator.values()) {
if (op.commutes && i > j) {
// no need to evaluate the same branch twice
continue;
}
try {
Expression expr = new OperationExpression(left, op, right);
if (expr.value == goal) {
System.out.println(expr);
} else {
solve(s.replace(i, j, expr));
}
} catch (ArithmeticException e) {
continue;
}
}
}
}
}
}
}
public static void main(String[] args) {
new Solver(812).solve(new State(75, 50, 2, 3, 8, 7));
}
}
}
As requested, each solution is reported only once (where two solutions are considered equal if their set of intermediary results is). Per Wikipedia description, not all numbers need to be used. However, there is a small bug left in that such solutions may be reported more than once.
What you're doing is basically a breadth-first search for a solution. This was also my initial idea when I saw the problem, but I would add a few things.
First, the main thing you're doing with your ArrayList is to remove elements from it and test if elements are already present. Since your range is small, I would use a separate HashSet, or BitSet for the second operation.
Second, and more to the point of your question, you could also add the final state to your initial points, and search backward as well. Since all your operations have inverses (addition and subtraction, multiplication and division), you can do this. With the Set idea above, you would effectively halve the number of states you need to visit (this trick is known as meet-in-the-middle).
Other small things would be:
Don't divide unless your resulting number is an integer
Don't add a number outside the range (so >999) into your set/queue
The total number of states is 999 (the number of integers between 1 and 999 inclusive), so you shouldn't really run into performance issues here. I'm thinking your biggest drain is that you're testing inclusion in an ArrayList which is O(n).
Hope this helps!
EDIT: Just noticed this. You say you check whether a number is already in the list, but then remove it. If you remove it, there's a good chance you're going to add it back again. Use a separate data structure (a Set works perfectly here) to store your visited states, and you should be fine.
EDIT 2: As per other answers and comments (thanks #kutschkem and #meriton), a proper Queue is better for popping elements (constant versus linear for ArrayList). In this case, you have too few states for it to be noticeable, but use either a LinkedList or ArrayDeque when you do a BFS.
Updated answer to solve Countdown
Sorry for my misunderstandings before. To solve countdown, you can do something like this:
Suppose your 6 initial numbers are a1, a2, ..., a6, and your target number is T. You want to check whether there is a way to assign operators o1, o2, ..., o5 such that
a1 o1 a2 ... o5 a6 = T
There are 5 operators, each can take one of 4 values, so there are 4 ^ 5 = 2 ^ 10 possibilities. You can use less than the entire 6, but if you build your solution recursively, you will have checked all of them at the end (more on this later). The 6 initial numbers can also be permuted in 6! = 720 ways, which leads to a total number of solutions of 2 ^ 10 * 6! which is roughly 720,000.
Since this is small, what I would do is loop through every permutation of the initial 6 numbers, and try to assign the operators recursively. For that, define a function
void solve(int result, int index, List<Integer> permutation)
where result is the value of the computation so far, and index is the index in the permutation list. You then loop over every operator and call
solve(result op permutation.get(index), index + 1, permutation)
If at any point you find a solution, check to see if you haven't found it before, and add it if not.
Apologies for being so dense before. I hope this is more to the point.
Your problem is analogous to a Coin Change Problem. First do all of the combinations of subtractions so that you can have your 'unit denomination coins' which should be all of the subtractions and additions, as well as the normal numbers you are given. Then use a change making algorithm to get to the number you want. Since we did subtractions beforehand, the result may not be exactly what you want but it should be close and a lot faster than what you are doing.
Say we are given the 6 numbers as the set S = {1, 5, 10, 25, 50, 75, 100}. We then do all the combinations of subtractions and additions and add them to S i.e. {-99, -95, -90,..., 1, 5, 10,..., 101, 105,...}. Now we use a coin change algorithm with the elements of S as the denominations. If we do not get a solution then it is not solvable.
There are many ways to solve the coin change problem, a few are discussed here:
AlgorithmBasics-examples.pdf

Recursion to get the number of different combinations of n people and k groups

I'm practicing recursion using Java and I've hit a problem. I'm trying to make a method which I'm calling "groups" which takes a number of people and how many groups there are and returns the number of different combinations there are of people and groups. Also, the ordering of people in the groups does not matter, nor does the ordering of the groups.
The code I have so far is:
public long groups(int n, int k) {
if(k==1) return 1;
if(k==n) return 1;
else return groups(n-1, k) + groups(n-1, k-1);
}
However it returns the wrong values. The first two lines are the base cases, which say if there is 1 group, then there is only one way to split the people up, makes sense. The other is when there are just as many people as there are groups, in which case theres only one way to split them up, one person into each group. The last statement is where I think I'm having problems, I would think that each time it does a recursive call, one person has to be taken out (n is the number of people, so n-1) and that person can ether join a group (k) or make their own group (k-1).
I'm just having a little trouble figuring out how recursion works and could use a little help.
These are the values I'm expecting:
groups(2,1) = 1
groups(2,2) = 1
groups(3,2) = 3
groups(4,2) = 7
groups(4,3) = 6
groups(5,3) = 25
There is something missing in the implementation of that part
... and that person can ether join a group (k) ...
I think the person can join 'k' groups, so the code must be
public long groups(int n, int k) {
if(k==1) return 1;
if(k==n) return 1;
else return k * groups(n-1, k) + groups(n-1, k-1);
}
(was missing multiplication by k)
There's a much easier (faster) way to compute combinations -- that's the binomial coefficient. While I can understand that your teacher may want you write a recursive function this way to become familiar with recursion, you can use this formula as a check.
In your case, you're reporting the wrong expected values here. What you want is
groups(2,1) = 2
groups(2,2) = 1
groups(3,2) = 3
groups(4,2) = 6
groups(4,3) = 4
groups(5,3) = 10
and the code you've posted is correct if the values above are what it's supposed to return.
(If not, perhaps you can better clarify the problem by explaining more clearly how the problem you're solving differs from the binomial coefficient.)

Staircase Problem - understanding the basic logic

Here is the recursive version of the staircase problem (There are N stairs, a person standing at the bottom wants to reach the top. The person can climb either 1 stair, 2 stairs or 3 stairs at a time. Count the number of different ways the person can reach the top.)
public static int findStep(int n)
{
if (n == 1 || n == 0)
return 1;
else if (n == 2)
return 2;
else
return findStep(n - 3) +
findStep(n - 2) +
findStep(n - 1);
}
My question is, why we are returning 1 when n=0 ??
To me, n=0 means there are no more stairs so it should return 0, but if I do so then the program doesn't work for other non-zero inputs. I saw similar questions in this site but non of those explain why we are returning 1 when there are no more stairs.
This is a selection problem. Think of the recurrence as the number of ways to select and order a combination of zero or more 1's, zero or more 2's, and zero or more 3's, that will together sum to n. There is only one way to make such a selection for n = 0: select none.
In this code n=0 means in the last step n was equal to 1or 2 or 3. in other words :
n-1=0 which means in the last step n=1, so there is one way to reach the top of stairs.
n-3=0 which means in the last step n=3, so one way to reach the top of stairs is to make 3 steps.
My question is, why we are returning 1 when n=0 ??
It means, there is only one possible way to reach 1st stair. You can understand more about it by going through https://medium.com/trick-the-interviwer/the-staircase-problem-9840b11201a5

Categories