在二维数组中找到最长的路径(如多米诺骨牌)

时间:2019-06-04 14:52:32

标签: java algorithm graph-algorithm

我需要从某个点找到最长的路径(就像多米诺骨牌一样),可以在文件中显示它:

domino

所以我可以从单元格(0,0)创建的最长的多米诺骨牌是(1,4)点,而不是(3,0)点。

我已经尝试使用dfs解决此问题,并且找到了整个区域的大小-我不知道如何更改此代码以计算多米诺骨牌的最长路径。

public class Main {

    static int totalRows = 4;
    static int totalCols = 6;
    static int[] rowNbr = {1, -1, 0, 0};
    static int[] colNbr = {0, 0, 1, -1};
    static int count = 0;
    static boolean[][] visited = new boolean[4][6];

    public static void main(String[] args) {
        int mat[][] = {
                {1, 0, 0, 0, 0, 0},
                {1, 1, 1, 1, 1, 0},
                {1, 0, 0, 0, 0, 0},
                {1, 0, 0, 0, 0, 0}};

        dfs(mat, 0, 0);
        System.out.println(count);
    }

    static void dfs(int[][] matrix, int startRow, int startCol) {    
        visited[startRow][startCol] = true;
        for (int k = 0; k < 4; k++) {
            int row1 = startRow + rowNbr[k];
            int col1 = startCol + colNbr[k];
            if (isValid(row1, col1)) {
                if (!visited[row1][col1] && matrix[row1][col1] == 1) {
                    count++;
                    dfs(matrix, row1, col1);
                }
            }
        }
    }

    static boolean isValid(int row, int col) {
        if (row < 0 || row > totalRows - 1) return false;
        if (col < 0 || col > totalCols - 1) return false;
        return true;
    }
}

1 个答案:

答案 0 :(得分:5)

您的深度优先搜索问题似乎在于您将所访问的每个字段都计算在内。不管字段是否是最长路径的一部分。

因此,如果您像这样更改代码,它应该可以工作:

public class Main {

    static int totalRows = 4;
    static int totalCols = 6;
    static int[] rowNbr = {1, -1, 0, 0};
    static int[] colNbr = {0, 0, 1, -1};
    //static int count = 0; //count is no longer needed
    static boolean[][] visited = new boolean[4][6];

    public static void main(String[] args) {
        int mat[][] = {{1, 0, 0, 0, 0, 0}, //
                {1, 1, 1, 1, 1, 0}, //
                {1, 0, 0, 0, 0, 0}, //
                {1, 0, 0, 0, 0, 0}};

        int maxDepth = dfs(mat, 0, 0, 1);
        System.out.println(maxDepth);

        //test second row {1, 1, 0, 0, 0, 0} like Damien mentioned
        mat = new int[][] {{1, 0, 0, 0, 0, 0}, //
                {1, 1, 0, 0, 0, 0}, //
                {1, 0, 0, 0, 0, 0}, //
                {1, 0, 0, 0, 0, 0}};
        visited = new boolean[4][6];

        maxDepth = dfs(mat, 0, 0, 1);
        System.out.println(maxDepth);

        //test a loop
        mat = new int[][] {{1, 0, 0, 0, 0, 0}, //
                {1, 1, 1, 1, 1, 0}, //
                {1, 0, 0, 0, 1, 0}, //
                {1, 1, 1, 1, 1, 0}};
        visited = new boolean[4][6];

        maxDepth = dfs(mat, 0, 0, 1);
        System.out.println(maxDepth);

        //test problem case
        mat = new int[][] {{1, 0, 1, 1, 0, 0}, //
                {1, 1, 1, 1, 1, 1}, //
                {1, 0, 0, 0, 0, 1}, //
                {1, 0, 0, 0, 0, 0}};
        visited = new boolean[4][6];

        maxDepth = dfs(mat, 0, 0, 1);
        System.out.println(maxDepth);
    }

    static int dfs(int[][] matrix, int startRow, int startCol, int depth) {//added a parameter for the recursion depth here
        visited[startRow][startCol] = true;
        int maxDepth = depth;//the maximum depth is the current recursion depth (until you find a deeper one)
        for (int k = 0; k < 4; k++) {
            int row1 = startRow + rowNbr[k];
            int col1 = startCol + colNbr[k];
            if (isValid(row1, col1)) {
                if (!visited[row1][col1] && matrix[row1][col1] == 1) {
                    int newDepth = dfs(matrix, row1, col1, depth + 1);//find the next cell in the path
                    if (newDepth > maxDepth) {//if the path is deeper than the deepest known path update the length
                        maxDepth = newDepth;
                    }
                }
            }
        }
        return maxDepth;
    }

    static boolean isValid(int row, int col) {
        if (row < 0 || row > totalRows - 1)
            return false;
        if (col < 0 || col > totalCols - 1)
            return false;
        return true;
    }
}

此代码在递归中找到最深的路径,并且仅当新长度大于当前最长路径时才更新最大长度。

它仍然使用深度优先搜索。我添加了更多测试用例,以表明它适用于所有输入字段:

第一个测试用例是您在问题中提供的测试:

int mat[][] = {{1, 0, 0, 0, 0, 0}, //
                {1, 1, 1, 1, 1, 0}, //
                {1, 0, 0, 0, 0, 0}, //
                {1, 0, 0, 0, 0, 0}};

输出为6,这似乎是正确的。

第二个测试是评论中提到的测试案例Damien:

//test second row {1, 1, 0, 0, 0, 0} like Damien mentioned
mat = new int[][] {{1, 0, 0, 0, 0, 0}, //
        {1, 1, 0, 0, 0, 0}, //
        {1, 0, 0, 0, 0, 0}, //
        {1, 0, 0, 0, 0, 0}};
visited = new boolean[4][6];//reset visited for the next test

这里的输出为4,似乎是正确的(因为在这种情况下,深度优先搜索仍然有效)。

第三个测试是循环:

//test a loop
mat = new int[][] {{1, 0, 0, 0, 0, 0}, //
        {1, 1, 1, 1, 1, 0}, //
        {1, 0, 0, 0, 1, 0}, //
        {1, 1, 1, 1, 1, 0}};
visited = new boolean[4][6];

输出为13。仍然正确。

第四个测试是一个测试用例,我认为这是有问题的,但它似乎也可以工作:

//test problem case
mat = new int[][] {{1, 0, 1, 1, 0, 0}, //
        {1, 1, 1, 1, 1, 1}, //
        {1, 0, 0, 0, 0, 1}, //
        {1, 0, 0, 0, 0, 0}};
visited = new boolean[4][6];

输出为10,也很正确。

需要进行更多测试,以验证它对每个输入都有效,但是对于大多数输入而言,它都可以正常工作。