【问题标题】:Recursive headache复发性头痛
【发布时间】:2015-09-18 15:54:54
【问题描述】:

任务

给定一个包含全非负数的二维数组m,我们将定义一个“路径”作为相邻单元格的集合(对角线步骤不算邻居)从row == 0 && col == 0 开始并以row == m.length - 1 && col == m[0].length - 1 结束。

“路径”的成本是“路径”的每个单元格中的值的总和。

示例:

数组中的两个可能路径:

路径1的成本(虚线):8 + 4 + 2 + 8 + 9 + 9 + 7 + 5 = 52;

路径2的成本(全线):8 + 6 + 3 + 8 + 9 + 4 + 1 + 2 + 1 + 7 + 6 + 5 = 60

待办事项:

编写一个static 递归方法,该方法接受一个二维数组m,其中填充了整个非负值,并打印所有可能路径成本的总和(您可以假设m 是不是null 也不是空的)。

方法签名是(允许重载):

public static void printPathWeights(int [][] m)

我的代码:

public class Main {

    public static void main(String[] args) {

        int arr[][] = { { 1, 1, 1 },
                        { 1, 1, 1 },
                        { 1, 1, 1 }
        };

        printPathWeights(arr);

    }

    public static void printPathWeights(int[][] m) {
        System.out.println(printPathWeights(m, 0, 0, new int[m.length][m[0].length], 0));
    }


    /*
     * @param map marks the visited cells
     */
    private static int printPathWeights(int[][] m, int row, int col, int[][] map, int carrier) {

        if (row < 0 || col < 0 || row >= m.length || col >= m[0].length || map[row][col] == 1)
            return 0;

        if (row == m.length - 1 && col == m[0].length - 1)
            return m[row][col] + carrier;

        map[row][col] = 1;
        return printPathWeights(m, row + 1, col, map, carrier + m[row][col]) +
                printPathWeights(m, row - 1, col, map, carrier + m[row][col]) +
                printPathWeights(m, row, col + 1, map, carrier + m[row][col]) +
                printPathWeights(m, row, col - 1, map, carrier + m[row][col]);

    }

}

上面代码的打印值为:14

低于预期!

当运行时:

    int arr[][] = { { 1, 1 },
                    { 1, 1 }
    };

结果如预期的那样是 6。

我的代码有什么问题?

PS:请不要向我提供解决任务的代码,但请解释我的代码有什么问题。

【问题讨论】:

  • 地图[行][列] = 1;再考虑一下这个逻辑
  • 我假设 map 应该是 visited 地图?如果是这样,请考虑以下探索顺序:路径 1:down,路径 2:leftdownright .探索在此处停止,因为您已经访问了路径 1 中的此节点。
  • @HunterLarco 将当前的 row col 标记为 1 有什么问题?
  • @DimaMaligin 假设两条不同的路径访问同一个单元格。用 1 标记单元格意味着它已被访问。所以第一条路径到达单元格,它被标记为已访问。第二条路径到达单元格,但它已被标记为已访问 -> 路径的结尾,尽管它会继续该单元格。

标签: java arrays recursion


【解决方案1】:

正如 Paul 所说,您的代码需要的更改是在递归调用之后恢复已访问的单元格集。它按预期打印76

public class Main {

    public static void main(String[] args) {

        int arr[][] = { { 1, 1, 1 },
                        { 1, 1, 1 },
                        { 1, 1, 1 }
        };

        printPathWeights(arr);

    }

    public static void printPathWeights(int[][] m) {
        System.out.println(printPathWeights(m, 0, 0, new int[m.length][m[0].length], 0));
    }

    /*
     * @param map marks the visited cells
     */
    private static int printPathWeights(int[][] m, int row, int col, int[][] map, int carrier) {

        if (row < 0 || col < 0 || row >= m.length || col >= m[0].length || map[row][col] == 1)
            return 0;

        if (row == m.length - 1 && col == m[0].length - 1)
            return m[row][col] + carrier;

        map[row][col] = 1;
        int result = printPathWeights(m, row + 1, col, map, carrier + m[row][col]) +
                printPathWeights(m, row - 1, col, map, carrier + m[row][col]) +
                printPathWeights(m, row, col + 1, map, carrier + m[row][col]) +
                printPathWeights(m, row, col - 1, map, carrier + m[row][col]);
        map[row][col] = 0;  // Here
        return result;
    }
}

【讨论】:

  • 是的,你是对的。但是你做了我要求不要做的一件事,那就是编写可以解决问题的代码,我确实为你的努力(我真的这样做)而坦克你,你得到了我的 +1。但请注意,一个好的答案应该考虑到提出问题的人应该从答案中学习而不是复制它。
【解决方案2】:

只要任意路径到达该单元格,该代码就会标记所访问的单元格。但是这个单元格随后被标记为所有其他单元格的已访问,并且不会再次被访问。这意味着该算法仅完成路径的一个子集,并且一些遍历在数组中间的某处中断以获得更大的数组。您必须将每个路径的单元格分别标记为已访问。

每次访问新单元后只需重置地图:

    printPathWeights(...)
        //analyze the current cell
        markCellVisited(currentCell)

        int tmp = visitAllNeighbours()

        resetVisitedState(currentCell)

        return tmp

这将是最有效和最简单的方法。由于在访问单元后单元状态被重置,它永远不会保持从先前路径标记。

【讨论】:

  • 所以基本上在每次通话中我都应该创建一个新的“克隆”地图并在克隆上标记单元格?
  • 似乎我错误地假设传递的map 是一个完全不同的数组。但我错了,因为每次递归调用都会更改原始地图。谢谢!
  • 虽然您的回答是正确的(我感谢您;)),但我必须补充一点,不完整的路径会返回 0,包括子路径,因此任何不完整的路径都计为 0 添加到总数中。我可能是错的,如果是这样,请扩展这个问题。
  • @DimaMaligin 哦,你是对的。我只是误解了部分代码。对不起
【解决方案3】:

在我看来,您一次只在一次递归中计算所有单元格的权重之和。但不考虑路径可能相交以及任何两条路径可以有共同单元格的事实。就像图中所示的两条路径有共同的单元格,并且必须添加两次

【讨论】:

  • 我确实考虑过。问题是我认为地图会根据当前路径进行更新,但我错了。
猜你喜欢
  • 2019-02-11
  • 2012-07-29
  • 1970-01-01
  • 1970-01-01
  • 2015-03-26
  • 1970-01-01
  • 2010-11-08
  • 2012-09-07
  • 1970-01-01
相关资源
最近更新 更多