回溯算法卡住了

Posted

技术标签:

【中文标题】回溯算法卡住了【英文标题】:Backtracking algorithm gets stuck 【发布时间】:2017-05-13 11:30:29 【问题描述】:

我有一个从左上角开始的矩阵(地图)问题,我想找到到右下角较轻的路径。它具有只能向右、向下或向右向下移动的条件。

这是一个例子: matrix example

我需要解决回溯的问题,但我不知道我是否做得很好。

这段代码能够解决最大 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;
 

是否有可能因为我不使用边界而被卡住?还是执行不好? 我不知道我做错了什么。我想我理解这个算法,但我想我不知道如何为这个问题实现它......

【问题讨论】:

您是否尝试使用调试器单步执行您的代码? 当您说I need to solve it using backtracking 时,这是否意味着虽然您知道回溯可能不是最佳解决方案,但您仍想尝试使用回溯解决它? 在尝试递归/迭代解决方案时,我总是会在最大递归/迭代次数上设置一个中断条件,这样您至少有机会检查中间解决方案,而不是永远等待跨度> 是的,我尝试使用调试器,但它似乎运行良好,至少第一次递归调用...是的,我知道这可能不是最好的解决方案,但我需要解决它回溯。 @JDLK7 至少是第一次递归调用,所以很明显错误是在进一步的调用中。继续单步调试代码,直到找到代码开始出现异常的地方。或者另一种可能性:您让代码运行一段时间,然后使用调试器附加到您的代码,以调查当前状态。 【参考方案1】:

虽然回溯会在这里给你正确的答案。在这种情况下,这不是最快的解决方案。

你在这里做了很多重复的工作,这是不必要的。在这种情况下,直接回溯是没有用的。让我们看看这个例子,

假设网格大小为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)

当第一次遍历到达点 (5,5) 时,它将继续寻找所有可能的方式去 (9,9)。现在,当第二次遍历达到 (5,5) 时,它将完成与第一次遍历在此阶段所做的完全相同的工作,第三次遍历也是如此。因此,这些重复的步骤是您耗尽程序并且代码执行时间过长的地方。您的代码不会被卡住,它只是运行了很长时间。您可以在此处轻松记住结果以优化时间。

因此,如果您可以将第一次到达点 (i,j) 时找到的值保存为 save[i][j],那么当其他一些遍历到达同一点 (i,j) 时,它可以决定不遍历任何点进一步并使用此save[i][j] 自己。这样,您可以使代码更快。

这样,它会变得更像是动态编程而不是回溯,即使是 10000X10000 大小的网格也需要大约几秒钟才能给出结果。

在这个答案中,我只描述了如何找到通往最小值的路径的值,如果您想找到也可以使用相同的 DP 解决方案的路径。

【讨论】:

以上是关于回溯算法卡住了的主要内容,如果未能解决你的问题,请参考以下文章

回溯算法 ------回溯算法的设计思想和适用条件

回溯算法 ------ 回溯算法的设计思想及适用条件

回溯算法及题目

回溯0--递归回溯算法框架

回溯与。贪心算法最大独立集

回溯算法思想回溯算法解题模板与回溯算法题目索引(不断更新)