Cover "Manhattan skyline" using the minimum number of rectangles - java

I write to solve a Codility problem provided below,
You are going to build a stone wall. The wall should be straight and N meters long, and its thickness should be constant; however, it should have different heights in different places. The height of the wall is specified by an array H of N positive integers. H[I] is the height of the wall from I to I+1 meters to the right of its left end. In particular, H[0] is the height of the wall's left end and H[N−1] is the height of the wall's right end.
The wall should be built of cuboid stone blocks (that is, all sides of such blocks are rectangular). Your task is to compute the minimum number of blocks needed to build the wall.
Write a function:
class Solution { public int solution(int[] H); }
that, given an array H of N positive integers specifying the height of the wall, returns the minimum number of blocks needed to build it.
For example, given array H containing N = 9 integers:
H[0] = 8 H[1] = 8 H[2] = 5
H[3] = 7 H[4] = 9 H[5] = 8
H[6] = 7 H[7] = 4 H[8] = 8
the function should return 7. The figure shows one possible arrangement of seven blocks.
Assume that:
N is an integer within the range [1..100,000];
each element of array H is an integer within the range [1..1,000,000,000].
Complexity:
expected worst-case time complexity is O(N);
expected worst-case space complexity is O(N) (not counting the storage required for input arguments).
I write a solution for the provided problem. The algorithm and code is provided below,
Algorithm
i. set block count = 1 and start iterating from the 2nd element of the array
ii. if the current depth is same as previous, keep going
iii. If the current depth is higher, push that in the stack and increase the count
iv. If the current depth is lower, keep poping till the current depth >= peek. Afterward, if the stack size = 0 or higher, increase the block count by 1
The code,
public static int solution(int[] H) {
Stack<Integer> stack = new Stack<>();
stack.push(H[0]);
int count = 1;
int N = H.length;
for (int i = 1; i < N; i++) {
if (H[i] == stack.peek()) {
continue;
} else if (H[i] > stack.peek()) {
stack.push(H[i]);
count++;
} else {
while (!stack.isEmpty() && H[i] < stack.peek()) {
stack.pop();
}
stack.push(H[i]);
count++;
}
}
return count;
}
The solution doesn't provide the correct answer and I can't find the bug even after spending some time in debugging. Can anyone see that?
The test set is provided below and the answer is 7 (I get 8).
int[] H = new int[9];
H[0] = 8;
H[1] = 8;
H[2] = 5;
H[3] = 7;
H[4] = 9;
H[5] = 8;
H[6] = 7;
H[7] = 4;
H[8] = 8;
Thank you.

Python Solution
Here is my solution
Solution with steps details
Codility python 100%
def solution(H):
"""
Codility 100%
https://app.codility.com/demo/results/trainingQKD6JP-PHA/
Idea is to use stack concept
Compute the minimum number of blocks needed to build the wall.
To build the wall start taking blocks of height one by one.
We need to take care of -
- the blocked should not be used again
- this is done only up to blocks height is greater than current
- why we are using last 8 height block if there is already 8 height block used in previous step?
reason is 8 is not present in stack top
8,
8,----- can not use because on stack top 8 is already there
5,
7,
9,
8,
7,------ can not use because on stack top 7 is already there
4,
8,
This is just example with height, see steps of output for details
skip8 skip7
| |
| | | |
| | | | |
| | | | |
| | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
Used blocks-
8
5
7
9
8
4
8
"""
block_count = 0
# stack is used to hold height used to building and remove all the blocks from it,
# if any of the block of stack is greater than current block(to be added for building)
stack = []
for height in H:
print(" ")
print("Current Height " + str(height))
print("Current stack " + str(stack))
# Remove all blocks that are bigger than current height, stack should not be empty
while stack and stack[-1] > height:
stack.pop()
print("After remove bigger blocks than current height " + str(stack))
# stack is not empty and top item of stack is equal to current height
if stack and stack[-1] == height:
# Already used this size of block
print("Already used this size of block " + str(height))
continue
else:
# new block is required, push it's size to the stack
block_count += 1
stack.append(height)
print("Add this block.... " + str(height) + " Minimum Blocks " + str(block_count))
return block_count

Another one in Java. Simpler, because I used assumption that height > 0.
public int solution(int[] hs) {
int squares = 0;
Stack<Integer> s = new Stack<>();
s.push(0);
for (int h: hs) {
while (s.peek() > h) {
s.pop();
}
if (s.peek() != h) {
s.push(h);
++squares;
}
}
return squares;
}

I find the bug and though it may be good to share. The reason is the new height is lesser than the peek value, we will keep popping the entities. So if the stack is not empty, the new height will be the same or higher than the stack peeks value.
If the new height will be the same, it means we already add a block for the height and will not add a new block. A condition is needed for the situation,
if (!stack.isEmpty() && H[i] == stack.peek()) {
continue;
}
The code is provided below provides 100% score,
public int solution(int[] H) {
Stack<Integer> stack = new Stack<>();
stack.push(H[0]);
int count = 1;
int N = H.length;
for (int i = 1; i < N; i++) {
if (H[i] == stack.peek()) {
continue;
} else if (H[i] > stack.peek()) {
stack.push(H[i]);
count++;
} else {
while (!stack.isEmpty() && H[i] < stack.peek()) {
stack.pop();
}
/*
* the new entity is either in same elevation or higher
* */
/*
* if in same elevation, we already added the block, so keep iterating
* */
if (!stack.isEmpty() && H[i] == stack.peek()) {
continue;
}
stack.push(H[i]);
count++;
}
}
return count;
}

If someone is still interested in this exercise, I share my Python solution (100% in Codility)
def solution(H):
stack, count = [], 1
for i in H:
if stack:
if i == stack[-1]:
continue
if i < stack[-1]:
while stack and stack[-1] > i:
stack.pop()
if stack:
if i > stack[-1]:
count+=1
stack.append(i)
else:
count+=1
stack.append(i)
else:
stack.append(i)
return count

Ruby 100%
def solution(h)
h.inject([1, [h.first]]) do |(blocks, stack), n|
next [blocks+1, stack.push(n)] if stack.last < n
stack.pop while stack.any? && stack.last > n
next [blocks, stack] if stack.last == n
[blocks+1, stack.push(n)]
end.first
end

A simpler java solution.
public int solution(int[] H) {
//block count
int count = 0;
// stack is used to hold height used to building and remove all the blocks from it,
// if any of the block of stack is greater than current block(is to be added for building)
Deque<Integer> stack = new ArrayDeque<>();
for (int a : H) {
// Remove all blocks that are bigger than current height, stack should not be empty
while (!stack.isEmpty() && a < stack.peek()) {
stack.pop();
}
//new block is required, push it's size to the stack
if (stack.isEmpty() || a > stack.peek()) {
count++;
stack.push(a);
}
}
return count;
}

My 100% JavaScript solution with O(N) time complexity:
function solution(H) {
let numBlocks = 0;
const blocksHeights = [0];
for (const height of H) {
while (blocksHeights[blocksHeights.length - 1] > height) {
blocksHeights.pop();
}
if (blocksHeights[blocksHeights.length - 1] !== height) {
blocksHeights.push(height);
numBlocks++;
}
}
return numBlocks;
}

in c# (100% in Codility)
public int solution(int[] H) {
Stack<int> stack = new Stack<int>();
stack.Push(H[0]);
int count = 1;
for (int i = 1; i < H.Length; i++)
{
if (H[i] == stack.Peek())
{
continue;
}
else if (H[i] > stack.Peek())
{
stack.Push(H[i]);
count++;
}
else
{
while (!(stack.Count==0) && H[i] < stack.Peek())
{
stack.Pop();
}
if (!(stack.Count==0) && H[i] == stack.Peek()) {
continue;
}
stack.Push(H[i]);
count++;
}
}
return count;
}

100% C++ in Codility
#include <stack>
int solution(vector<int> &H) {
int cnt{0};
std::stack<int> reusedStone;
for (auto h : H) {
if (reusedStone.empty() || (h > reusedStone.top())) {
reusedStone.push(h); cnt++;
} else if (h < reusedStone.top()) {
while ((!reusedStone.empty()) && (h < reusedStone.top())) {
reusedStone.pop();
}
if ((!reusedStone.empty()) && (h == reusedStone.top())) {
continue;
} else {
reusedStone.push(h); cnt++;
}
}
}
return cnt;
}

My python solution (100% success rate on Codility)
import math
def solution(H):
nb_blocks = 0
horizon = [math.inf]
for h in H:
while horizon and h < horizon[-1]:
horizon.pop()
if (horizon and h > horizon[-1]) or (not horizon):
horizon.append(h)
nb_blocks += 1
return nb_blocks

Related

binary search divide by 4

Binary search divide array in 2 parts. But what if I want to divide the array in 4 parts ?
Here is my approach
while (low <= h){
quartal = (low + high) / 4;
if (array[quartal] == x) return quartal;
if (array[2*quartal] == x) return 2*quartal;
if (array[3*quartal] == x) return 3*quartal;
if (array[4*quartal] == x) return 4*quartal;
if (array[quartal] > x) high = quartal-1;
if (array[quartal] < x && array[2*quartal] > x){
low = quartal + 1;
high = 2*quartal-1;
}
if (array[2*quartal] < x && array[3*quartal] > x){
low = quartal + 1;
high = 2*quartal -1;
}
if (array[3*quartal] < x && array[4*quartal] > x){
low = 2*quartal + 1;
high = 3*quartal -1;
}
if (array[4*quartal] < x){
low = 3*quartal + 1;
}
that work but not for all values.
can someone tell me what wrong with my approach?
To answer your question:
Is your array sorted? Binary search only works on sorted arrays.
In the last if-statement, you check if array[4*quartal] < x. Note that this can lead to errors, as quartal is an integer, and therefore 4*quartal will not be equal to (low + high) but rather 4*floor((low+high)/4). Therefore, you may be dividing into 5 segments instead of 5 depending on if (low+heigh) is multiple of 4.
Because 4*quartal should be the end of the segment in your array which you are searching in, I would suggest replacing 4*quartal by (low+high).
I hope this does help.
In addition to what CodingTil has said.
You will have to do the following when doing your checks. Try to think of what would happen with edge cases like a length of 103 or just an array of [0,1]. In your code if we had an array length of 103, we would divide by 4 and get quartels of length 25.75. This can be problematic if we floor the quartel at the start as you'll miss out on values at index 101 and above. You'll have to adjust your other if statements in a similar manner.
if (array[floor(quartal)] == x) return floor(quartal);
if (array[floor(2*quartal)] == x) return floor(2*quartal);
if (array[floor(3*quartal)] == x) return floor(3*quartal);
if (array[high] == x) return high; // should be a whole number so no need to round
Your seventh if statement has an error (your eighth if statement will also have to be adjusted), it should read as follows. And I believe you'll be able to get rid of the ninth if statement altogether.
if (array[floor(2*quartal)] < x && array[floor(3*quartal)] > x){
low = floor(2*quartal) + 1;
high = floor(3*quartal) -1;
}
// high remains unchanged, as we are in the highest quartal
if (array[floor(3*quartal)] < x && array[floor(4*quartal)] > x){
low = floor(3*quartal) + 1;
}

Find the first element in a sorted array that is smaller than the target

In a sorted array, you can use binary search to perform many different kinds of operations:
to find the first element smaller than the target
to find the first element bigger than the target
or,
to find the first element smaller or equal than the target
to find the first element bigger or equal than the target
or even specific
to find the element closest to the target.
You can find answers to #2 and #5 in stack overflow, the answer of which are using mutations of binary search, however there is no fixed algorithm to answer those questions, specifically in adjusting the indices.
For example, in question 3, find the first smaller or equal element in sorted array than target:
Given int[] stocks = new int[]{1, 4, 3, 1, 4, 6};, I want to find the first element smaller than 5. It should return 4 after sorting and my code goes like:
private static int findMin(int[] arr, int target) {
Arrays.sort(arr);
int lo = 0;
int hi = arr.length - 1;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (arr[mid] == target) return mid;
if (arr[mid] > target) {
hi = mid - 1;
} else {
lo = mid;
}
}
return lo;
}
The logic here is:
if you find mid element equals to target, you just return the mid
if you find mid element bigger than the target, you just discard the mid and everything bigger than it
if you find mid element is smaller than the target, the mid element could be an answer, you want to keep it, but discard anything smaller than it.
If you run it, it actually goes into a infinite loop, but just tweak the start index of hi = arr.length - 1 to hi = arr.length;, it actually works well. I have no clue how to really set all the conditions up: how to write conditions, what to set start index of hi and lo and use lo<=hi or lo < hi.
Any help?
Basically in the above mentioned case ,you need the greatest element which is smaller than the given value, i.e you need to find floor of the given element.
This can be easily done using binary search in O(logn), time :
The cases which you need to consider are as follows:
If last element is smaller than x, than return the last element.
If middle point is floor, than return mid.
If element is not found in both of the above cases, than check if the element lies between mid and mid -1. If it is so than return mid-1.
Else keep iterating on left half or right half until you find a element that satisfies your condition. Select right half or left half based on the check that given value is greater than mid or less than mid.
Try the following:
static int floorInArray(int arr[], int low, int high, int x)
{
if (low > high)
return -1;
// If last element is smaller than x
if (x >= arr[high])
return high;
// Find the middle point
int mid = (low+high)/2;
// If middle point is floor.
if (arr[mid] == x)
return mid;
// If x lies between mid-1 and mid
if (mid > 0 && arr[mid-1] <= x && x < arr[mid])
return mid-1;
// If x is smaller than mid, floor
// must be in left half.
if (x < arr[mid])
return floorInArray(arr, low, mid - 1, x);
// If mid-1 is not floor and x is
// greater than arr[mid],
return floorInArray(arr, mid + 1, high,x);
}
In your while loop, you don't have a case set for when hi == lo
This case is applicable when you are iterating the last element or array has only 1 element.
Set the while loop as while(lo <= hi) and it will terminate when all elements are searched
Or set an if case inside loop for when hi is equal to lo.
if(hi == lo)
Rather than implementing your own binary search, you can just use Arrays.binarySearch(int[] a, int key), then adjust the returned value accordingly.
Returns index of the search key, if it is contained in the array; otherwise, (-(insertion point) - 1). The insertion point is defined as the point at which the key would be inserted into the array: the index of the first element greater than the key, or a.length if all elements in the array are less than the specified key. Note that this guarantees that the return value will be >= 0 if and only if the key is found.
Your rules didn't specify which index to return when there are multiple valid choices (#3 or #4 with multiple equal values, or #5 with equidistant values), so the code below has code making an explicit choice. You can remove the extra code, if you don't care about ambiguities, or change the logic if you disagree with my decision to resolve it.
Note that when return value is <0, returnValue = -insertionPoint - 1, which means that insertionPoint = -returnValue - 1, which in code below mean -idx - 1. Index prior to insertion point is therefore -idx - 2.
The methods may of course return out-of-range index values (-1 or arr.length), so caller always need to check for that. For closest() method, that can only happen if array is empty, in which case it returns -1.
public static int smaller(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx < 0) {
// target not found, so return index prior to insertion point
return -idx - 2;
}
// target found, so skip to before target value(s)
do {
idx--;
} while (idx >= 0 && arr[idx] == target);
return idx;
}
public static int smallerOrEqual(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx < 0) {
// target not found, so return index prior to insertion point
return -idx - 2;
}
// target found, so skip to last of target value(s)
while (idx < arr.length - 1 && arr[idx + 1] == target) {
idx++;
}
return idx;
}
public static int biggerOrEqual(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx < 0) {
// target not found, so return index of insertion point
return -idx - 1;
}
// target found, so skip to first of target value(s)
while (idx > 0 && arr[idx - 1] == target) {
idx--;
}
return idx;
}
public static int bigger(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx < 0) {
// target not found, so return index of insertion point
return -idx - 1;
}
// target found, so skip to after target value(s)
do {
idx++;
} while (idx < arr.length && arr[idx] == target);
return idx;
}
public static int closest(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx >= 0) {
// target found, so skip to first of target value(s)
while (idx > 0 && arr[idx - 1] == target) {
idx--;
}
return idx;
}
// target not found, so compare adjacent values
idx = -idx - 1; // insertion point
if (idx == arr.length) // insert after last value
return arr.length - 1; // last value is closest
if (idx == 0) // insert before first value
return 0; // first value is closest
if (target - arr[idx - 1] > arr[idx] - target)
return idx; // higher value is closer
return idx - 1; // lower value is closer, or equal distance
}
Test
public static void main(String... args) {
int[] arr = {1, 4, 3, 1, 4, 6};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
System.out.println(" | Index | Value |");
System.out.println(" | < <= ~ >= > | < <= ~ >= > |");
System.out.println("--+----------------------+---------------------+");
for (int i = 0; i <= 7; i++)
test(arr, i);
}
public static void test(int[] arr, int target) {
int smaller = smaller (arr, target);
int smallerOrEqual = smallerOrEqual(arr, target);
int closest = closest (arr, target);
int biggerOrEqual = biggerOrEqual (arr, target);
int bigger = bigger (arr, target);
System.out.printf("%d | %3d %3d %3d %3d %3d |%3s %3s %3s %3s %3s | %d%n", target,
smaller, smallerOrEqual, closest, biggerOrEqual, bigger,
(smaller < 0 ? "" : String.valueOf(arr[smaller])),
(smallerOrEqual < 0 ? "" : String.valueOf(arr[smallerOrEqual])),
(closest < 0 ? "" : String.valueOf(arr[closest])),
(biggerOrEqual == arr.length ? "" : String.valueOf(arr[biggerOrEqual])),
(bigger == arr.length ? "" : String.valueOf(arr[bigger])),
target);
}
Output
[1, 1, 3, 4, 4, 6]
| Index | Value |
| < <= ~ >= > | < <= ~ >= > |
--+----------------------+---------------------+
0 | -1 -1 0 0 0 | 1 1 1 | 0
1 | -1 1 0 0 2 | 1 1 1 3 | 1
2 | 1 1 1 2 2 | 1 1 1 3 3 | 2
3 | 1 2 2 2 3 | 1 3 3 3 4 | 3
4 | 2 4 3 3 5 | 3 4 4 4 6 | 4
5 | 4 4 4 5 5 | 4 4 4 6 6 | 5
6 | 4 5 5 5 6 | 4 6 6 6 | 6
7 | 5 5 5 6 6 | 6 6 6 | 7
Try Treesets. If your input is array, follow below steps:
convert array to hash set .
src:https://www.geeksforgeeks.org/program-to-convert-array-to-set-in-java/
2.convert hash set to Tree set.
Tree sets will store the values in sorted order with no duplicates.
Now, call Tree set methods like higher(),ceiling(),floor(),lower() methods as per your requirement.

simplest MiniMax algorithm for TicTacToe AI in Java

I was trying to get a grasp of MiniMax algorithm, and have read up on it. My initial approach was to implement a simple MiniMax algorithm, and then to add alpha-beta pruning. However this is my current code:
public int miniMax(char[] node, int playerNum)
{
int victor = checkWin(node); // returns 0 if game is ongoing, 1 for p1, 2 for p2, 3 for tie.
if(victor != 0) //game over .
return score(victor);
if(playerNum == 2) //AI
{
int bestVal = Integer.MIN_VALUE;
int bestSpot = 0;
for(int i = 0; i < node.length; i++)
{
if(node[i] != '-')
continue;
node[i] = getSymbol(playerNum);
int value = miniMax(node, 1);
if(value > bestVal)
{
bestVal = value;
bestSpot = i;
}
node[i] = '-';
}
return bestSpot;
}
else
{
int bestVal = Integer.MAX_VALUE;
int bestSpot = 0;
for(int i = 0; i < node.length; i++)
{
if(node[i] != '-')
continue;
node[i] = getSymbol(playerNum);
int value = miniMax(node, 2);
if(value < bestVal)
{
bestVal = value;
bestSpot = i;
}
node[i] = '-';
}
return bestSpot;
}
}
And my score function
private int Score(int gameState)
{
if(gameState ==2) //O wins.
return 10;
else if(gameState==1) //X wins
return -10;
return 0;
}
Now, I have a working AI that tries to block my move and win, however sometimes it is making non-intelligent choices for instance this is the output I get if my input read from console is 6,7,8 in that order. It does not attempt to block my win. But in other cases it does.
| O | O | |
| | | |
| X | X | X |
In my second attempt I tried 4,3 and it blocked my winning move.
| | O | |
| X | X | O |
| | | |
I was wondering anyone could point out what is wrong with my implementation?
The behavior of the code for the shown examples is correct!
So why is the threat in the following position not blocked? Why does the program play move 1 instead of 6?
O . . O 1 2
. . . numbering available moves: 3 4 5
X X . X X 6
It is because if the game is lost on perfect play the program just plays the first available move.
The algorithm only cares about win or loss and not in how many moves.
See what happens if the threat is blocked:
O . . O . .
. . . . X . and X wins on his next move
X X O X X O

Java Sudoku solver backtracking

I'm trying to build a sudoku solver. I know my code is messy and there will probably be a much simpler way to do it, but I would like finish the algorithm the way I started.
The algorithm starts doing what I want (filling the blank spaces with the first number that could fit), but when it reaches a point with no options, I don't know how to go back and erase the last number I inserted to try with another combination. But I can't just erase the last number from the matrix because it could be a number that wasn't placed by the algorithm.
If someone could help I would really appreciate it.
public class Backtracking{
public static void Sudoku(int[][] sudokuTable){
if (isAnswer(sudokuTable)){
printSudoku(sudokuTable);
}else{
for (int j = 1; j <=9; j++){
if (canfit(sudokuTable, j)){
addToSudoku(sudokuTable, j);
printSudoku(sudokuTable);
Sudoku(sudokuTable);
}
}
}
}
public static void addToSudoku(int[][] sudokuTable, int n){
int i = 0;
int j = 0;
boolean done = false;
while (i < 9 && !done){
while (j < 9 && !done){
if (sudokuTable[i][j] == 0){
sudokuTable[i][j] = n;
done = true;
}
j++;
}
i++;
}
}
public static void printSudoku(int[][] sudokuTable){
for (int i = 0; i < 9; i++){
for (int j = 0; j < 9; j++){
System.out.print(sudokuTable[i][j] + " ");
}
System.out.println();
}
System.out.println();
}
public static boolean isAnswer(int[][] sudokuTable){
int sum = 0;
for (int i = 0; i < 9; i++){
for (int j = 0 ; j < 9; j++){
if (sudokuTable[i][j] > 9 || sudokuTable[i][j] < 1)
return false;
else
sum++;
}
}
if (sum != 405)
return false;
return true;
}
public static boolean canfit(int[][] sudokuTable, int n){
int i = 0;
int j = 0;
boolean pos = false;
boolean fit = true;
while (i < 9 && !pos){
while (j < 9 && !pos){
if (sudokuTable[i][j] == 0)
pos = true;
else
j++;
}
if (!pos)
i++;
}
for (int k = 0; k < 9; k++){
if (sudokuTable[i][k] == n && k != j)
fit = false;
}
if (fit){
for (int l = 0; l < 9; l++){
if(sudokuTable[l][j] == n && l != i)
fit = false;
}
}
if (fit){
if (i >= 0 && i < 3)
i = 0;
else if (i >=3 && i < 6)
i = 3;
else if (i >=6 && i < 9)
i = 6;
if (j >= 0 && j < 3)
j = 0;
else if (j >=3 && j < 6)
j = 3;
else if (j >=6 && j < 9)
j = 6;
for (int m = i; m < i+3; m++){
for (int o = j; o < j+3; o++){
if (sudokuTable[m][o] == n)
fit = false;
}
}
}
return fit;
}
Try to return true or false from your Sudoko method.
when isAnswer() method returns true, print table. Then return true from Sudoko() method.
Now inside your for loop, where you are calling Sudoko() method recursively, check if it returns true, or false. If it returns true, that means your choice is correct and it leads to a solution, you need not to do anything else. If it returns false, remove the number you set using addToSudoko() method. Make the table as it was before calling addToSudoko() method and continue iterating.
And if your for loop, loops for 9 times and none of the number has a suitable spot, that means if loop ends, return false.
Hope this helps
Actually you can backtracking moves by using an array, each time a move is wrong you just start to remove some moves and try a different move, however this has a problem:
the complexity of trying all possible moves is huge (how long does it takes to try all digits on a number with 81 digits? even if you cut computation time here and there , you will need all the time of the universe)
the main problem in sudoku is that you have no clue which was the wrong move if you move randomly.
Assume the following case sudoky with 2x2 cells:
+----+----++-----+-----+
| 1 | 2 || 3 | 4 |
+----+----++-----+-----+
| 4 | 3 || 1 | 2 |
+====+====++=====+=====+
| 2 | 1 || 4 | 3 |
+----+----++-----+-----+
| 3 | 4 || 2 | 1 |
+----+----++-----+-----+
If you use your algorithm in the following (unsolved) case:
+----+----++-----+-----+
| 1 | || | 4 |
+----+----++-----+-----+
| | || | |
+====+====++=====+=====+
| 2 | || | |
+----+----++-----+-----+
| | 4 || | 1 |
+----+----++-----+-----+
it is possible he will run into the following sequence
+----+----++-----+-----+
| 1 | || 2 | 4 |
+----+----++-----+-----+
| | || 2 | |
+====+====++=====+=====+
| 2 | || | |
+----+----++-----+-----+
| | 4 || | 1 |
+----+----++-----+-----+
Actually the added "twos" are both wrong, but when your algorithm find that those are wrong because you have 2 "twos" in the same column, you don't know which one was the wrong one (the first added, the second added, or both?)
A correct backtracking algorithm would works like this:
You start with a 81 cells arrays, and you start placing numbers (in sequence).
.
for(int i=0; i<81; i++)
array[i] = TryNumber();
.
then you check after each added number if that was correct.
.
if(SomeNumberNotCorrect())
break; // you know you can stop "tryingnumbers" so you can save on loop executions
.
But you don't know which was the wrong number
Now writing a correct algorithm that solves sudokus by attemps and do not run in million of years is pretty long and I cannot write it here but I don't think the way you choosen is the best. The best way is to apply the same strategies used by players. Just keep in mind that if you want an algorithm to resolve sudokus in a similiar way to how Chess is played by computer your algorithm would require much more time than a Chess game (infact a computer cannot analize chess moves more than 5-6 turns). But infact Sudokus can be resolved with much faster algorithms.
Instead I've already done in past a simple solver you could actually try to apply the same strategies a player would use to solve it:
In example:
For each cell, check if current Sector, Column and Line have already all numbers except 1, then you can add that number. And to check that for each cells you just need 81*81*81 moves.
When your solver do not find anymore solutions on a Sudoku, it is just because you have to develop as player a new strategy and then you need to apply it to your program, in short you will have a program that will be able to solve every sudoku (not very hard, and actually this is the reason that there are a lot of free sudoku solvers out there).

Calculating how far a robot will move in Java

I'm working on a project for school that requires me to move a robot. How far the robot will move each second (variable t) is calculated by the function below.
The first function is easy. The 2nd and 3rd on the other are where I'm stuck. How would I write F(t-1)? Below is what I have so far.
if (t == 0) {
distance = 2;
} else if (t > 0 && <=6 || t > 12) {
// No clue on how to write the 2nd distance equation.
} else if (t >= 7 && <=12) {
// No clue on how to write the 3rd distance equation.
}
Recursion really isn't necessary to solve this.
Note that in each of the non-zero time cases, F(t) = F(t-1) + something.
So you can simply do:
double f = 2; /* Initial value at t=0 */
for (int t = 1; t <= maxT; ++t) { // maxT is the maximum value of t.
if (t <= 6 || t > 12) {
f += /* something for case 2 */;
} else {
f += /* something for case 3 */;
}
}
System.out.println(f);
You can do this with recursion, but you will get a StackOverflowError if maxT becomes modestly large; by contrast, using a loop will work for arbitrarily large maxT (modulo floating point errors).
As pointed out by #Andreas, you can do this without looping over all values of t:
double f = 2 * (maxT + 1);
for (int t = 7; t <= maxT && t <= 12; ++t) {
f += log(t) - 2;
}
and you can eliminate that loop too by precomputing the values.
This is a problem which involves the use of recursion. By and large, pay close attention to the notation Ft-1, since that refers to an evaluation of the specific function at t-1.
I won't write out all of the code, but I'll give you some of the basics:
When t = 0, return 2. This is your base case.
When t is between 0 and 6 inclusive or greater than 12, return an evaluation of the function at t-1 and add 2.
When t is between 7 and 12 both inclusive, return an evaluation of the function at t-1 and add log2(t).
Here's something to get you at least started in the right direction.
public double evaluateDistance(int t) {
if(t == 0) {
return 2;
} else if(t > 0 && t <= 6) || (t > 12) {
// Think about this - it would involve another call to evaluateDistance, but what is t again?
} else if(t >= 7 && t <= 12) {
// Another evaluation involving the function.
// For free, the change of base operation you'll need to get base-2 evaluation for the log:
return ??? + Math.log(t)/Math.log(2);
}
}
Think I figured it out. Sorry if I wasn't clear on what I needed, just needed to figure out how to write the equations in the function. Think I figured it out though.
public double move()
{
int t = 0;
if(t == 0) // After the first second, robot moves 2
{
distance = 2;
}
else if(t > 0 && t <= 6 || t > 12) // From seconds 0 to 6 and after 12, robot moves distance equation
{
distance = (2*t)+2;
}
else if(t >= 7 && t <= 12) // From seconds 7 to 12, robot moves distances equation
{
distance = (2*t)+(Math.log(t)/Math.log(2));
}
position = position + distance;
return position;
}
}

Categories

Resources