簡體   English   中英

遞歸頭痛

[英]Recursive headache

任務

給定一個包含整個非負數的二維數組m ,我們將一個“路徑”定義為相鄰單元格的集合(對角線步驟不算作鄰居 )從row == 0 && col == 0開始row == 0 && col == 0並以row == m.length - 1 && col == m[0].length - 1結束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接受2D陣列遞歸方法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:請不要向我提供解決作業的代碼,但要解釋我的代碼有什么問題。

一旦任意路徑到達該單元,代碼就標記訪問的單元。 但是此細胞隨后被標記為所有其他細胞的訪問,並且不再被訪問。 這意味着該算法僅完成路徑的子集,並且一些遍歷在陣列中間的某處中斷以獲得更大的陣列。 您必須將單元格標記為每個路徑單獨訪問。

只需在每次訪問新單元格后重置地圖:

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

        int tmp = visitAllNeighbours()

        resetVisitedState(currentCell)

        return tmp

這將是最有效和最簡單的方法。 由於在訪問單元格后復位了cellstate,因此它將永遠不會保留前一個路徑的標記。

正如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;
    }
}

在我看來,你只在一次遞歸中計算所有單元格的權重之和。 但不考慮路徑可能相交的事實,並且任何兩條路徑都可以有共同的單元格。就像圖中所示的兩條路徑具有共同的單元格並且必須添加兩次

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM