📜  在给定约束条件下找到矩阵中的最长路径

📅  最后修改于: 2021-04-29 02:23:23             🧑  作者: Mango

给定一个* n矩阵,其中所有数字都是不同的,请找到最大长度路径(从任何单元格开始),以使路径上的所有单元格都以递增顺序排列,相差1。

我们可以从给定的像元(i,j)向4个方向移动,即我们可以移动到(i + 1,j)或(i,j + 1)或(i-1,j)或(i,j -1),条件是相邻像元的差为1。

例子:

Input:  mat[][] = {{1, 2, 9}
                   {5, 3, 8}
                   {4, 6, 7}}
Output: 4
The longest path is 6-7-8-9. 

这个想法很简单,我们计算从每个单元格开始的最长路径。一旦计算出所有单元的最长,就返回所有最长路径的最大值。这种方法的一个重要发现是许多重叠的子问题。因此,可以使用动态编程来最佳地解决此问题。

以下是基于动态编程的实现,该实现使用查找表dp [] []来检查问题是否已解决。

C/C++
// C++ program to find the longest path in a matrix
// with given constraints
#include 
#define n 3
using namespace std;
  
// Returns length of the longest path beginning with mat[i][j].
// This function mainly uses lookup table dp[n][n]
int findLongestFromACell(int i, int j, int mat[n][n], int dp[n][n])
{
    if (i < 0 || i >= n || j < 0 || j >= n)
        return 0;
  
    // If this subproblem is already solved
    if (dp[i][j] != -1)
        return dp[i][j];
  
    // To store the path lengths in all the four directions
    int x = INT_MIN, y = INT_MIN, z = INT_MIN, w = INT_MIN;
  
    // Since all numbers are unique and in range from 1 to n*n,
    // there is atmost one possible direction from any cell
    if (j < n - 1 && ((mat[i][j] + 1) == mat[i][j + 1]))
        x = 1 + findLongestFromACell(i, j + 1, mat, dp);
  
    if (j > 0 && (mat[i][j] + 1 == mat[i][j - 1]))
        y = 1 + findLongestFromACell(i, j - 1, mat, dp);
  
    if (i > 0 && (mat[i][j] + 1 == mat[i - 1][j]))
        z = 1 + findLongestFromACell(i - 1, j, mat, dp);
  
    if (i < n - 1 && (mat[i][j] + 1 == mat[i + 1][j]))
        w = 1 + findLongestFromACell(i + 1, j, mat, dp);
  
    // If none of the adjacent fours is one greater we will take 1
    // otherwise we will pick maximum from all the four directions
    return dp[i][j] = max(x, max(y, max(z, max(w, 1))));
}
  
// Returns length of the longest path beginning with any cell
int finLongestOverAll(int mat[n][n])
{
    int result = 1; // Initialize result
  
    // Create a lookup table and fill all entries in it as -1
    int dp[n][n];
    memset(dp, -1, sizeof dp);
  
    // Compute longest path beginning from all cells
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (dp[i][j] == -1)
                findLongestFromACell(i, j, mat, dp);
  
            // Update result if needed
            result = max(result, dp[i][j]);
        }
    }
  
    return result;
}
  
// Driver program
int main()
{
    int mat[n][n] = { { 1, 2, 9 },
                      { 5, 3, 8 },
                      { 4, 6, 7 } };
    cout << "Length of the longest path is "
         << finLongestOverAll(mat);
    return 0;
}


Java
// Java program to find the longest path in a matrix
// with given constraints
  
class GFG {
    public static int n = 3;
  
    // Function that returns length of the longest path
    // beginning with mat[i][j]
    // This function mainly uses lookup table dp[n][n]
    static int findLongestFromACell(int i, int j, int mat[][], int dp[][])
    {
        // Base case
        if (i < 0 || i >= n || j < 0 || j >= n)
            return 0;
  
        // If this subproblem is already solved
        if (dp[i][j] != -1)
            return dp[i][j];
  
        // To store the path lengths in all the four directions
        int x = Integer.MIN_VALUE, y = Integer.MIN_VALUE, z = Integer.MIN_VALUE, w = Integer.MIN_VALUE;
        // Since all numbers are unique and in range from 1 to n*n,
        // there is atmost one possible direction from any cell
        if (j < n - 1 && ((mat[i][j] + 1) == mat[i][j + 1]))
            x = dp[i][j] = 1 + findLongestFromACell(i, j + 1, mat, dp);
  
        if (j > 0 && (mat[i][j] + 1 == mat[i][j - 1]))
            y = dp[i][j] = 1 + findLongestFromACell(i, j - 1, mat, dp);
  
        if (i > 0 && (mat[i][j] + 1 == mat[i - 1][j]))
            z = dp[i][j] = 1 + findLongestFromACell(i - 1, j, mat, dp);
  
        if (i < n - 1 && (mat[i][j] + 1 == mat[i + 1][j]))
            w = dp[i][j] = 1 + findLongestFromACell(i + 1, j, mat, dp);
  
        // If none of the adjacent fours is one greater we will take 1
        // otherwise we will pick maximum from all the four directions
        return dp[i][j] = Math.max(x, Math.max(y, Math.max(z, Math.max(w, 1))));
    }
  
    // Function that returns length of the longest path
    // beginning with any cell
    static int finLongestOverAll(int mat[][])
    {
        // Initialize result
        int result = 1;
  
        // Create a lookup table and fill all entries in it as -1
        int[][] dp = new int[n][n];
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                dp[i][j] = -1;
  
        // Compute longest path beginning from all cells
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (dp[i][j] == -1)
                    findLongestFromACell(i, j, mat, dp);
  
                // Update result if needed
                result = Math.max(result, dp[i][j]);
            }
        }
  
        return result;
    }
  
    // driver program
    public static void main(String[] args)
    {
        int mat[][] = { { 1, 2, 9 },
                        { 5, 3, 8 },
                        { 4, 6, 7 } };
        System.out.println("Length of the longest path is " + finLongestOverAll(mat));
    }
}
  
// Contributed by Pramod Kumar


Python3
# Python3 program to find the longest path in a matrix
# with given constraints
  
n = 3
# Returns length of the longest path beginning with mat[i][j]. 
# This function mainly uses lookup table dp[n][n] 
def findLongestFromACell(i, j, mat, dp):
    # Base case 
    if (i<0 or i>= n or j<0 or j>= n):
        return 0
  
    # If this subproblem is already solved 
    if (dp[i][j] != -1): 
        return dp[i][j]
  
    # To store the path lengths in all the four directions
    x, y, z, w = -1, -1, -1, -1
  
    # Since all numbers are unique and in range from 1 to n * n, 
    # there is atmost one possible direction from any cell 
    if (j0 and (mat[i][j] +1 == mat[i][j-1])): 
        y = 1 + findLongestFromACell(i, j-1, mat, dp)
  
    if (i>0 and (mat[i][j] +1 == mat[i-1][j])):
        z = 1 + findLongestFromACell(i-1, j, mat, dp)
  
    if (i


C#
// C# program to find the longest path
// in a matrix with given constraints
using System;
  
class GFG {
    public static int n = 3;
  
    // Function that returns length of
    // the longest path beginning with mat[i][j]
    // This function mainly uses lookup
    // table dp[n][n]
    public static int findLongestFromACell(int i, int j,
                                           int[][] mat,
                                           int[][] dp)
    {
        // Base case
        if (i < 0 || i >= n || j < 0 || j >= n) {
            return 0;
        }
  
        // If this subproblem is
        // already solved
        if (dp[i][j] != -1) {
            return dp[i][j];
        }
  
        // To store the path lengths in all the four directions
        int x = int.MinValue, y = int.MinValue, z = int.MinValue, w = int.MinValue;
  
        // Since all numbers are unique and
        // in range from 1 to n*n, there is
        // atmost one possible direction
        // from any cell
        if (j < n - 1 && ((mat[i][j] + 1) == mat[i][j + 1])) {
            x = dp[i][j] = 1 + findLongestFromACell(i, j + 1, mat, dp);
        }
  
        if (j > 0 && (mat[i][j] + 1 == mat[i][j - 1])) {
            y = dp[i][j] = 1 + findLongestFromACell(i, j - 1, mat, dp);
        }
  
        if (i > 0 && (mat[i][j] + 1 == mat[i - 1][j])) {
            z = dp[i][j] = 1 + findLongestFromACell(i - 1, j, mat, dp);
        }
  
        if (i < n - 1 && (mat[i][j] + 1 == mat[i + 1][j])) {
            w = dp[i][j] = 1 + findLongestFromACell(i + 1, j, mat, dp);
        }
  
        // If none of the adjacent fours is one greater we will take 1
        // otherwise we will pick maximum from all the four directions
        dp[i][j] = Math.Max(x, Math.Max(y, Math.Max(z, Math.Max(w, 1))));
        return dp[i][j];
    }
  
    // Function that returns length of the
    // longest path beginning with any cell
    public static int finLongestOverAll(int[][] mat)
    {
        // Initialize result
        int result = 1;
  
        // Create a lookup table and fill
        // all entries in it as -1
        int[][] dp = RectangularArrays.ReturnRectangularIntArray(n, n);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                dp[i][j] = -1;
            }
        }
  
        // Compute longest path beginning
        // from all cells
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (dp[i][j] == -1) {
                    findLongestFromACell(i, j, mat, dp);
                }
  
                // Update result if needed
                result = Math.Max(result, dp[i][j]);
            }
        }
  
        return result;
    }
  
    public static class RectangularArrays {
        public static int[][] ReturnRectangularIntArray(int size1,
                                                        int size2)
        {
            int[][] newArray = new int[size1][];
            for (int array1 = 0;
                 array1 < size1; array1++) {
                newArray[array1] = new int[size2];
            }
  
            return newArray;
        }
    }
  
    // Driver Code
    public static void Main(string[] args)
    {
        int[][] mat = new int[][] {
            new int[] { 1, 2, 9 },
            new int[] { 5, 3, 8 },
            new int[] { 4, 6, 7 }
        };
        Console.WriteLine("Length of the longest path is " + finLongestOverAll(mat));
    }
}
  
// This code is contributed by Shrikant13


输出:

Length of the longest path is 4

上述解决方案的时间复杂度为O(n 2 )。乍看起来似乎更多。如果仔细研究,我们会发现dp [i] [j]的所有值仅计算一次。