Backtracking algorithm gets stuck - c++

I have this problem of a matrix (map) that starting from top-left corner, I want to find the less heavier path to bottom-right corner. It has the condition that it can only move right, down or right-down.
This is an example:
matrix example
I need to solve the problem with backtracking, but I can't tell if I'm doing it well.
This code is able to solve matrix sizes up to 10x10, but when I try a 20x20 matrix, it gets stuck (or at least that's what I think after hours).
/*
* i, j -> matrix iterators.
* n, m -> matrix height and width
* map -> matrix
* actualPath, bestPath -> vectors for representing the path later
* actual -> actual path weight
* best -> best path weight
*/
int backtracking(int i, int j, const int &n, const int &m,
const vector<vector<int>> &map,
vector<vector<int>> &actualPath,
vector<vector<int>> &bestPath,
int best) {
recursiveCalls++;
int actual = 0;
//Bottom-right corner
if(i == (n-1) && j == (m-1)) {
return map[i][j];
}
//Last row, only right
else if(i == (n-1)) {
actual = map[i][j] +
backtracking(i, (j+1), n, m, map, actualPath, bestPath, best, profundidad);
}
//Last column, only down
else if(j == (m-1)) {
actual = map[i][j] +
backtracking((i+1), j, n, m, map, actualPath, bestPath, best, profundidad);
}
else {
int downRight = backtracking((i+1), (j+1), n, m, map, actualPath, bestPath, best, profundidad);
int right = backtracking(i, (j+1), n, m, map, actualPath, bestPath, best, profundidad);
int down = backtracking((i+1), j, n, m, map, actualPath, bestPath, best, profundidad);
actual = map[i][j] + minimo(downRight, right, down);
}
if(actual < best) {
best = actual;
bestPath = actualPath;
}
return best;
}
Is it possible that it gets stuck because I don't use bounds? Or is it bad implemented?
I don't know what I'm doing wrong. I think I understand this algorithm but I guess I don't know how to implement it for this problem...

Although backtracking will give you the correct answer here. It is not the fastest solution in this case.
You are doing a lot duplicate work here, which are not necessary. Straightforward Backtracking is not useful in this case. Lets take a look at this example,
suppose the grid size is 10X10.
one of the trees of the backtrackting stared from (0,0) -> (0,1)
another started from (0,0) -> (1,0)
and another started from (0,0) -> (1,1)
When the 1st traversal reaches point (5,5) it will keep finding all possible ways to go to (9,9). Now the 2nd traversal when that reaches (5,5) it will do the exact same work the first traversal did from this stage, and so will the 3rd traversal. So these duplicate steps are the places where you are exhausting your program and your code is taking way too long to execute. Your code is not stuck its just running for very long time. You can memoize the results easily to optimize the time here.
So if you can save the value that you found when you first reached a point (i,j) as save[i][j], then when some other traversal reaches this same point(i,j) it can decide not to traverse any further and use this save[i][j] for its own. This way you can make the code lot more faster.
This way it will become more of dynamic programming than backtracking, and even a grid of size 10000X10000 will take around few seconds to give you the results.
In this answer I only described how to find the value of the path towards min value, if you want to find the path thats also possible using the same DP solution.

Related

Why does only backtracking work in this scenario?

I am solving this question on LeetCode.com:
In a gold mine grid of size m * n, each cell in this mine has an integer representing the amount of gold in that cell, 0 if it is empty. Return the maximum amount of gold you can collect under the conditions:- (a) Every time you are located in a cell you will collect all the gold in that cell; (b) From your position you can walk one step to the left, right, up or down. (c) You can't visit the same cell more than once; (d) Never visit a cell with 0 gold. (e) You can start and stop collecting gold from any position in the grid that has some gold.
For the grid: [[0,6,0],[5,8,7],[0,9,0]] the output is: 24.
I wrote the code below:
class Solution {
public:
int dig(vector<vector<int>>& grid, int i, int j) {
if(i>=grid.size() || i<0 || j>=grid[0].size() || j<0 || grid[i][j]==0) return 0;
//change begins...
int gold=0;
gold+=grid[i][j];
grid[i][j]=0;
gold+=max(dig(grid, i+1, j), max(dig(grid, i, j+1), max(dig(grid, i-1, j), dig(grid, i, j-1))));
return gold;
//change ends...
}
int getMaximumGold(vector<vector<int>>& grid) {
vector<vector<int>> gridCopy=grid;
int maxGold=0;
for(int i=0; i<grid.size(); i++) {
for(int j=0; j<grid[0].size(); j++) {
if(grid[i][j]!=0) {
maxGold=max(maxGold, dig(gridCopy, i, j));
gridCopy=grid;
}
}
}
return maxGold;
}
};
However, it breaks on the input [[1,0,7,0,0,0],[2,0,6,0,1,0],[3,5,6,7,4,2],[4,3,1,0,2,0],[3,0,5,0,20,0]]; yielding 58 instead of 60.
There's another code that I found here, which is identical, except in the commented part above, wherein they have the below lines instead:
g[i][j] = -g[i][j];
auto res = max({ dfs(g, i + 1, j), dfs(g, i, j + 1), dfs(g, i - 1, j), dfs(g, i, j - 1) });
g[i][j] = -g[i][j];
return g[i][j] + res;
(And of course, they don't assign grid to gridCopy in the nested for loop, since they revert the modified grid back to its original form).
I understand they are backtracking, while I am not. But I am unable to understand what I am doing incorrect, since logically, I am doing the exact same thing. I used debug statements to trace the issue, but it is becoming difficult to follow along since there are many recursive calls.
Could someone please point out what is the logical fallacy in my code above?
Thanks!
All your recursive calls might modify the grid, and don't restore it.
That means that the first visit to a cell will block it for all other subsequent attempts.
For instance, if dig(grid, i+1, j) is evaluated first, none of the cells that were visited during that computation are available when you do the other three directions.
If your code happens to start in the top left corner and go downwards first in your example, you will visit 1-2-3-4-3 and get stuck.
After that walk, there is no path from the top left corner any more, even though there were plenty of them from the beginning, and some of them pay a lot more than 13.
(You might think that you're going to find a path from either direction, but it depends on the evaluation order.)
Shared mutable state and recursion is a very tricky combination.
One thing which seems wrong in your code is:
//change begins...
int gold=0;
gold+=grid[i][j];
grid[i][j]=0;
gold+=max(dig(grid, i+1, j), max(dig(grid, i, j+1), max(dig(grid, i-1, j), dig(grid, i, j-1))));
return gold;
//change ends...
Here you have mutated the value of grid[i][j] and that changed value is impacting your input, i.e. your input set is wrong now. Since the value of the grid[i][j] is changed and thus this will impact the rest of the calculation.
What you can do is store the initial value of grid[i][j] somewhere in that recursion stack and reassign back to the grid[i][j] after you are done exploring all paths from that node.
eg: a slight modification in your logic
//change begins...
int gold=0;
gold+=grid[i][j];
int temp = grid[i][j];
grid[i][j]=0;
gold+=max(dig(grid, i+1, j), max(dig(grid, i, j+1), max(dig(grid, i-1, j), dig(grid, i, j-1))));
grid[i][j] = temp;
return gold;
//change ends...
You can also save creating a memory in your recursion stack if you use the solution there in your question.
Just to answer your concern why only backtracking can solve this problem:
You need to understand your solution, which seems like:
look at each grid item if that can be part of the solution set.
for that, you select one grid item (where item value should be greater than 0)
then you explore all surroundings from that item. And using DFS you keep on exploring their surroundings and their surroundings, etc, until the exit condition is met.
Now, in your solution, you have mutated the value of grid[i][j] (for understanding purpose, let us say grid[2][3] is mutated) which is fine if and only if that item selected is present in the final solution set.
But, while exploring other possibilities, if you may happen to find some possibility with a greater number of golds present. Then there also grid[2][3] will be involved. Which you have marked as 0, i.e. the calculation for that node will go wrong.
So, you need to restore the original value to the grid item grid[i][j]. The reason you are making that 0 is you don't want to include it again as you have already visited. But for other solution sets, you need the original value to be present there.

Perfect shuffle and unshuffle, with no auxiliary array

Before any concrete question, please note that my goal is not to shuffle randomly the array, but to perform a perfect shuffle as the one a ideal dealer may do with a set of cards, that is, splitting the deck in half and performing one shuffle passage (interleaving a card from one half deck with one card from the other half). (This is actually one exercise from Algorithms in C third edition by Sedgewick: nbr 11.3 page 445)
So, i'm not interested in algorithms like Fisher-Yates shuffle etc.
Said that, my point is to avoid using any auxiliary array when performing the shuffle, the code I was able to deliver is the following:
template<typename T>
void two_way_shuffle(vector<T>& data,int l,int r)
{
int n=(r-l)+1;
int m=(r+l)/2;
if(n%2==0) ++m;
int s,p{l+1};
for(;p<=r;p+=2,m++)
{
s=data[m]; //Make space
//Shift the elements
for(int i{m};i>p;i--)
data[i]=data[i-1];
//Put the element in the final position
data[p]=s;
}
}
template<typename T>
void two_way_unshuffle(vector<T>& data,int l,int r)
{
int n=(r-l)+1;
if(n%2!=0){
--r;
--n;
}
int m=(r+l)/2;
int s,p{l+1},w{r-1};
for(;p<=w;p++,w--)
{
s=data[w];
for(int i{w};i>p;i--)
data[i]=data[i-1];
data[p]=s;
}
//Complete the operation
for(p=l+1,w=m;p<w;p++,w--)
swap(data[p],data[w]);
}
The basic idea beside the shuffling operation is to keep track of the position in the array 'p' where the next element should be inserted, then copying that element from the array data at position 'w' leaving one empty space, then shifting the array from left to right in order to move the empty space exactly to the position 'p', once that was done the code just move to data[p] the previously saved value 's'. Pretty simple.. And it looks to work properly (some shuffle examples)
FROM: 12345678
TO: 15263748
FROM: IS THIS WORKING CORRECTLY OR NOT?
TO: ICSO RTRHEICST LWYO ROKRI NNGO T?
FROM: SHUFFLING TEST
TO: SNHGU FTFELSIT
My very problem is in the unshuffle operation, I believe that the swap sequence in the last for loop can be avoided, but I'm not able to find a cleaver way to do that. The problem is that the main loop unshuffle performs a shift operation which eventually leave the elements of the first half of the array in the wrong order (thus, requiring the swap in the second for).
I'm almost sure there must be a clever way to do the job without such a code complication..
Do you have any suggestion on what may be improved in the unshuffle algorithm? Or any other suggestion on what I've done?
Thanks
I think your code keeps too many variables. When you shuffle the array, you are treating a range [lo, hi] of decreasing size, where you swap the rightmost entry hi with the block of elements to te left [lo, hi). You can express the algorithm just in terms of these two variables:
0 1 2 3 4 5
------- swap [1, 3) and [3]
0 3 1 2 4 5
---- swap [3, 4) and [4]
0 3 1 4 2 5
- [5, 5) is empty: break
This is the same for an odd number of elements, except that the empty range goes out of bound, which is okay, since we don't access it. The operations here are: shift block right, place old hi element at lo position, increase lo and hi with strides 2 and 1.
When you unshuffle, you must revert the steps: Start lo and hi at the last element for even-sized and one element beyond the array for odd-sized array. Then do all steps in reverse order: decrease lo and hi first, then shift the block left and place the old lo at hi position. Stop when lo reaches 1. (It will reach 1, because we've started at an odd index and we decrement by 2.)
You can test your algorithm by printing lo and hi as you go: They must be the same for shuffling and unshufling, only in reverse order.
So:
template<typename T>
void weave(std::vector<T>& data)
{
size_t lo = 1;
size_t hi = (data.size() + 1) / 2;
while (lo < hi) {
T m = data[hi];
for (size_t i = hi; i-- > lo; ) data[i + 1] = data[i];
data[lo] = m;
lo += 2;
hi++;
}
}
template<typename T>
void unweave(std::vector<T>& data)
{
size_t n = data.size();
size_t lo = n + n % 2 - 1;
size_t hi = lo;
while (hi--, lo-- && lo--) {
T m = data[lo];
for (size_t i = lo; i < hi; i++) data[i] = data[i + 1];
data[hi] = m;
}
}
I've removed the left and right indices, which makes the code less flexible, but hopefully clearer to read. You can put them back in and will only need them to calculate your initial values for lo and hi.
You can perform both these steps with a fixed number of swaps, at the cost of a non-linear index calculation step. But for practical applications the time cost of the swap usually drives the total time, so these algorithms approach O(N).
For perfect shuffling, see https://cs.stackexchange.com/a/105263/58310 (or https://cs.stackexchange.com/q/105604/58310 for an alternate explanation)
For unshuffling, a related algorithm is described here: https://stackoverflow.com/a/55112294/10396

Recursive Divide and Conquer Algorithm Modification

So in my textbook there is this block of code to find the maximum element in an array by using the divide and conquer recursive algorithm:
Item max(Item a[], int l, int r)
{
if (l == r) return a[1];
int m = (l+r)/2;
Item u = max(a, l, m);
Item v = max(a, m+1, r);
if (u > v) return u; else return v;
}
For one of the questions following the code, it asks me to modify that program so that I find the maximum element in an array by dividing an array of size N into one part of size k = 2^((lgN)-1) and another of size N-k (so that the size of at least one of the parts is a power of 2.
So I'm trying to solve that, and I just realized I wouldn't be able to do an exponent in code. How am I supposed to implement dividing one array into size k = 2^((lgN)-1)?
Both logs and exponentials can be computed using functions in the standard library.
But a simple solution would be to start at 1 and keep doubling until you reach a number bigger than desired. Going back one step then give you your answer.
(Of course the whole idea is mad - this algorithm is much more complex and slower than the obvious linear scan. But I'll assume there is some method in the madness.)
This finds maximum k being a power of 2 and less than the number of array items (so the array part is divided into two non-empty parts):
Item max(Item a[], int l, int r)
{
if (l == r) return a[r];
int s = r-l, k = 1;
while (2*k <= s)
k = 2*k;
Item u = max(a, l, l+k-1);
Item v = max(a, l+k, r);
return u > v ? u : v;
}
However this is not necessarily the best possible choice. For example you might want to seek such k which is closest to the half of the array's length (for 10 items that would be k=4 instead of 8).
Or you may try to partition the array into two parts both with lengths being powers of 2 (if possible, for 10 items it would be 8+2)...

Algorithm for finding the maximum number of non-overlapping lines on the x axis

I'm not exactly sure how to ask this, but I'll try to be as specific as possible.
Imagine a tetris screen with only rectangles, of different shapes, falling to the bottom.
I want to compute the maximum number of rectangles that I can fit one next to the other without any overlapping ones. I've named them lines in the title because I'm actually only interested in the length of the rectangle when computing, or the line parallel to the x axis that it's falling towards.
So basically I have a custom type with a start and end, both integers between 0 and 100. Say we have a list of these rectangles ranging from 1 to n. rectangle_n.start (unless it's the rectangle closest to the origin) has to be > rectangle_(n-1).end so that they will never overlap.
I'm reading the rectangle coordinates (both are x axis coordinates) from a file with random numbers.
As an example:
consider this list of rectangle type objects
rectangle_list {start, end} = {{1,2}, {3,5}, {4,7} {9,12}}
We can observe that the 3rd object has its start coordinate 4 < the previous rectangle's end coordinate which is 5. So in sorting this list, I would have to remove the 2nd or the 3rd object so that they don't overlap.
I'm not sure if there is a type for this kind of problem so I didn't know how else to name it. I'm interested in an algorithm that can be applied on a list of such objects and would sort them out accordingly.
I've tagged this with c++ because the code I'm writing is c++ but any language would do for the algorithm.
You are essentially solving the following problem. Suppose we have n intervals {[x_1,y_1),[x_2,y_2),...,[x_n,y_n)} with x_1<=x_2<=...<=x_n. We want to find a maximal subset of these intervals such that there are no overlaps between any intervals in the subset.
The naive solution is dynamic programming. It guarantees to find the best solution. Let f(i), 0<=i<=n, be the size of the maximal subset up to interval [x_i,y_i). We have equation (this is latex):
f(i)=\max_{0<=j<i}{f(j)+d(i,j)}
where d(i,j)=1 if and only if [x_i,y_i) and [x_j,y_j) have no overlaps; otherwise d(i,j) takes zero. You can iteratively compute f(i), starting from f(0)=0. f(n) gives the size of the maximal subset. To get the actual subset, you need to keep a separate array s(i)=\argmax_{0<=j<i}{f(j)+d(i,j)}. You then need to backtrack to get the 'path'.
This is an O(n^2) algorithm: you need to compute each f(i) and for each f(i) you need i number of tests. I think there should be a O(nlogn) algorithm, but I am not so sure.
EDIT: an implementation in Lua:
function find_max(list)
local ret, f, b = {}, {}, {}
f[0], b[0] = 0, 0
table.sort(list, function(a,b) return a[1]<b[1] end)
-- dynamic programming
for i, x in ipairs(list) do
local max, max_j = 0, -1
x = list[i]
for j = 0, i - 1 do
local e = j > 0 and list[j][2] or 0
local score = e <= x[1] and 1 or 0
if f[j] + score > max then
max, max_j = f[j] + score, j
end
end
f[i], b[i] = max, max_j
end
-- backtrack
local max, max_i = 0, -1
for i = 1, #list do
if f[i] > max then -- don't use >= here
max, max_i = f[i], i
end
end
local i, ret = max_i, {}
while true do
table.insert(ret, list[i])
i = b[i]
if i == 0 then break end
end
return ret
end
local l = find_max({{1,2}, {4,7}, {3,5}, {8,11}, {9,12}})
for _, x in ipairs(l) do
print(x[1], x[2])
end
The name of this problem is bin packing, it is usually considered as a hard problem but can be computed reasonably well for small number of bins.
Here is a video explaining common approaches to this problem
EDIT : By hard problem, I mean that some kind of brute force has to be employed. You will have to evaluate a lot of solutions and reject most of them, so usually you need some kind of evaluation mechanism. You need to be able to compare solution, such as "This solution packs 4 rectangles with area of 15" is better than "This solution packs 3 rectangles with area of 16".
I can't think of a shortcut, so you may have to enumerate the power set in descending order of size and stop on the first match.
The straightforward way to do this is to enumerate combinations of decreasing size. You could do something like this in C++11:
template <typename I>
std::set<Span> find_largest_non_overlapping_subset(I start, I finish) {
std::set<Span> result;
for (size_t n = std::distance(start, finish); n-- && result.empty();) {
enumerate_combinations(start, finish, n, [&](I begin, I end) {
if (!has_overlaps(begin, end)) {
result.insert(begin, end);
return false;
}
return true;
});
}
return result;
}
The implementation of enumerate_combination is left as an exercise. I assume you already have has_overlap.

How can I find number of consecutive sequences of various lengths satisfy a particular property?

I am given a array A[] having N elements which are positive integers
.I have to find the number of sequences of lengths 1,2,3,..,N that satisfy a particular property?
I have built an interval tree with O(nlogn) complexity.Now I want to count the number of sequences that satisfy a certain property ?
All the properties required for the problem are related to sum of the sequences
Note an array will have N*(N+1)/2 sequences. How can I iterate over all of them in O(nlogn) or O(n) ?
If we let k be the moving index from 0 to N(elements), we will run an algorithm that is essentially looking for the MIN R that satisfies the condition (lets say I), then every other subset for L = k also is satisfied for R >= I (this is your short circuit). After you find I, simply return an output for (L=k, R>=I). This of course assumes that all numerics in your set are >= 0.
To find I, for every k, begin at element k + (N-k)/2. Figure out if this defined subset from (L=k, R=k+(N-k)/2) satisfies your condition. If it does, then decrement R until your condition is NOT met, then R=1 is your MIN (your could choose to print these results as you go, but they results in these cases would be essentially printed backwards). If (L=k, R=k+(N-k)/2) does not satisfy your condition, then INCREMENT R until it does, and this becomes your MIN for that L=k. This degrades your search space for each L=k by a factor of 2. As k increases and approaches N, your search space continuously decreases.
// This declaration wont work unless N is either a constant or MACRO defined above
unsigned int myVals[N];
unsigned int Ndiv2 = N / 2;
unsigned int R;
for(unsigned int k; k < N; k++){
if(TRUE == TESTVALS(myVals, k, Ndiv2)){ // It Passes
for(I = NDiv2; I>=k; I--){
if(FALSE == TESTVALS(myVals, k, I)){
I++;
break;
}
}
}else{ // It Didnt Pass
for(I = NDiv2; I>=k; I++){
if(TRUE == TESTVALS(myVals, k, I)){
break;
}
}
}
// PRINT ALL PAIRS from L=k, from R=I to R=N-1
if((k & 0x00000001) == 0) Ndiv2++;
} // END --> for(unsigned int k; k < N; k++)
The complexity of the algorithm above is O(N^2). This is because for each k in N(i.e. N iterations / tests) there is no greater than N/2 values for each that need testing. Big O notation isnt concerned about the N/2 nor the fact that truly N gets smaller as k grows, it is concerned with really only the gross magnitude. Thus it would say N tests for every N values thus O(N^2)
There is an Alternative approach which would be FASTER. That approach would be to whenever you wish to move within the secondary (inner) for loops, you could perform a move have the distance algorithm. This would get you to your O(nlogn) set of steps. For each k in N (which would all have to be tested), you run this half distance approach to find your MIN R value in logN time. As an example, lets say you have a 1000 element array. when k = 0, we essentially begin the search for MIN R at index 500. If the test passes, instead of linearly moving downward from 500 to 0, we test 250. Lets say the actual MIN R for k = 0 is 300. Then the tests to find MIN R would look as follows:
R=500
R=250
R=375
R=312
R=280
R=296
R=304
R=300
While this is oversimplified, your are most likely going to have to optimize, and test 301 as well 299 to make sure youre in the sweet spot. Another not is to be careful when dividing by 2 when you have to move in the same direction more than once in a row.
#user1907531: First of all , if you are participating in an online contest of such importance at national level , you should refrain from doing this cheap tricks and methodologies to get ahead of other deserving guys. Second, a cheater like you is always a cheater but all this hampers the hard work of those who have put in making the questions and the competitors who are unlike you. Thirdly, if #trumetlicks asks you why haven't you tagged the ques as homework , you tell another lie there.And finally, I don't know how could so many people answer this question this cheater asked without knowing the origin/website/source of this question. This surely can't be given by a teacher for homework in any Indian school. To tell everyone this cheater has asked you the complete solution of a running collegiate contest in India 6 hours before the contest ended and he has surely got a lot of direct helps and top of that invited 100's others to cheat from the answers given here. So, good luck to all these cheaters .