简体   繁体   English

回溯算法陷入困境

[英]Backtracking algorithm gets stuck

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). 这段代码能够解决最大10x10的矩阵,但是当我尝试使用20x20的矩阵时,它会卡住(或者至少我几个小时后才想到)。

/*
 * 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 . 假设网格大小为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). 当第一个遍历到达点(5,5)时,它将继续寻找所有可能的前往(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. 现在,当第二遍历达到(5,5)时,它将完成与该阶段的第一次遍历完全相同的工作,因此第三遍历也将完成。 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. 因此,如果您可以将首次到达点(i,j)时发现的值另存为save[i][j] ,则当其他遍历到达该点(i,j)时,它可以决定不进行遍历并进一步使用此save[i][j] 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. 这样,它将变成动态编程而不是回溯,甚至大小为10000X10000的网格也将花费大约几秒钟的时间来提供结果。

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. 在此答案中,我仅描述了如何找到通向最小值的路径的值,如果您想使用相同的DP解决方案也可以找到该路径。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM