Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/358.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 基于动态规划的矩阵最大遍历代价_Java_Algorithm_Dynamic Programming - Fatal编程技术网

Java 基于动态规划的矩阵最大遍历代价

Java 基于动态规划的矩阵最大遍历代价,java,algorithm,dynamic-programming,Java,Algorithm,Dynamic Programming,假设我有一个Java中的mxn矩阵 我想找出从第一列到最后一列的最大遍历开销。每个值代表发生的成本。我可以在矩阵中上下左右移动。每个单元只能访问一次。允许从列的顶部单元格过渡到同一列的底部,反之亦然 为简单起见,考虑以下矩阵: 2 3 17 4 1 -1 5 0 14 如果我想找出最大成本,我的答案是46(2)→ 5.→ 4.→ 1.→ 3.→ 0→ 14→ 17) 我尝试使用以下递归关系使用动态方法解决此问题: maxCost(of destination node) = max{ max

假设我有一个Java中的
mxn
矩阵

我想找出从第一列到最后一列的最大遍历开销。每个值代表发生的成本。我可以在矩阵中上下左右移动。每个单元只能访问一次。允许从列的顶部单元格过渡到同一列的底部,反之亦然

为简单起见,考虑以下矩阵:

2 3 17
4 1 -1
5 0 14
如果我想找出最大成本,我的答案是46(2)→ 5.→ 4.→ 1.→ 3.→ 0→ 14→ 17)

我尝试使用以下递归关系使用动态方法解决此问题:

maxCost(of destination node) = max{ maxCost(at neighbouring node 1), maxCost(at neighbouring node 2), maxCost(at neighbouring node 3) } + cost(of destination node)
在这种情况下,它将类似于:

maxCost(17) = max{ maxCost(3), maxCost(-1), maxCost(14) } + 17;
由于每个单元格只允许访问一次,我知道我需要维护相应的
mxn
isvisted
矩阵。但是,我不知道如何维护
isvisted
矩阵。当计算maxCost(3)时,将修改矩阵;但是对于maxCost(-1)和maxCost(14),我需要它的初始状态(将丢失)

我的方法对这个问题正确吗?而且,我不知道我的函数应该是什么样子。
(这是我第一次尝试动态编程)。

这是一次艰难的尝试。请注意,由于您的路径不能重复访问的单元格,因此可能的路径将具有“蛇形”行为,例如:

其思想是在
f[j][i]
中存储以单元
(j,i)
结束的路径的最大长度。现在让我们假设我们想要从
f[j][i-1]
过渡到
f[j'][i]
。然后,我们可以选择直接从cell
(j,i)
转到cell
(j',i)
,也可以通过环绕顶部/底部边缘从cell
(j,i)
转到cell
(j',i)
。因此,
f[j][i]
的更新可以计算为:

在哪里

这里
a
是给定的数组

现在的问题是如何有效地计算
sum(a[j..j'][i]
,因为否则运行时将是
O(m^3n)
。您可以通过为
sum(a[j..j'][i])
使用一个临时变量
tmp_sum
来解决这个问题。然后,算法的运行时间将是
O(m^2 n)

下面是一个示例实现:

package stackoverflow;

public class Solver {

    int m, n;
    int[][] a, f;

    public Solver(int[][] a) {
        this.m = a.length;
        this.n = a[0].length;
        this.a = a;
    }

    void solve(int row) {
        f = new int[m][n];
        for (int i = 0; i < m; ++i)
            for (int j = 0; j < n; ++j)
                f[i][j] = Integer.MIN_VALUE;

        for (int i = 0; i < n; ++i) {
            int sum = 0;
            for (int j = 0; j < m; ++j)
                sum += a[j][i];
            for (int j1 = 0; j1 < m; ++j1) {
                int tmp_sum = 0;
                boolean first = true;
                for (int j2 = j1; j2 != j1 || first; j2 = (j2+1)%m) {
                    if (first)
                        first = false;
                    tmp_sum += a[j2][i];
                    int best_sum = Math.max(tmp_sum, sum - tmp_sum +a[j1][i]+a[j2][i]);
                    if (j1 == j2)
                        best_sum = a[j1][i];
                    int prev = 0;
                    if (i > 0)
                        prev = f[j1][i-1];
                    f[j2][i] = Math.max(f[j2][i], best_sum + prev);
                }
            }
        }

        System.out.println(f[row][n-1]);
    }

    public static void main(String[] args) {
        new Solver(new int[][]{{2, 3, 17}, {4, 1, -1}, {5, 0, 14}}).solve(0); //46
        new Solver(new int[][]{{1, 1}, {-1, -1}}).solve(0); //2
    }
}
包堆栈溢出;
公共类求解器{
int m,n;
int[]a,f;
公共解算器(int[][]a){
这.m=a.长度;
this.n=a[0]。长度;
这个a=a;
}
无效解算(整数行){
f=新整数[m][n];
对于(int i=0;i0)
prev=f[j1][i-1];
f[j2][i]=数学最大值(f[j2][i],最佳和+上一个);
}
}
}
系统输出打印项次(f[行][n-1]);
}
公共静态void main(字符串[]args){
新的解算器(新的int[][{{2,3,17},{4,1,-1},{5,0,14})。解算(0);//46
新解算器(新int[][{{1,1},{-1,-1}})。解算(0);//2
}
}

这是一个很好的问题,也有点棘手。对于DP解决方案,我们必须用与

这就要求我们定义一个“状态”,这样问题就可以用一个n向决策来描述,这个决策将我们带到一个新的状态,而这个状态又是同一问题的一个新的、更小的版本

一个合适的状态选择是遍历的当前位置加上一个带符号的整数f,它表示当前列中有多少未遍历(我称之为“空闲”)行。我们可以将其写成三元组[I,j,f]

f的值告诉我们是否可以向上和/或向下移动。(除非我们在右列中,否则总是可以向右移动,并且永远不可能向左移动。)如果f为负,则“上方”有f个空闲行当前位置,可能环绕到矩阵底部。如果为正值,则下面有
f
空闲行。请注意,f=m-1和f=1-m的意思相同:除了当前位置之外,所有行都是空闲的。为简单起见,我们将使用f==m-1来表示这种情况

我们只需要一个整数f来描述自由空间,因为我们只能以大小为1的步长遍历,而且我们永远不会向左移动。因此,在同一列中不能有非连续的自由空间组

现在,DP“决定”是一个4向选择:

  • 在当前方格处原地踏步:仅在最后一列中有效
  • 上移:仅当上方有可用空间时有效
  • 下移:仅当下方有可用空间时有效
  • 向右移动:除最后一列外有效
  • 假设,C(t)是DP中的最大成本函数,其中t是一个三重[i,j,f]。那么,我们可以实现的最大成本是,在做出上述最佳决策1到4之后,矩阵中的成本a[i,j]加上剩余遍历的成本。最佳决策就是产生最高成本的决策

    所有这些使得C成为所有元素都是有条件的集合的最大值

    C[i,j,f] = max { A[i,j] if j==n-1, // the "stand pat" case
                   { A[i,j]+C[i,j+1,m-1] if j<n-1  // move right
                   { A[i,j]+C[i+1,j,f-1] if f>0    // move down
                   { A[i,j]+C[i-1,j,2-m] if f==m-1 // first move in col is up
                   { A[i,j]+C[i-1,j,f+1] if f<0    // other moves up
    
    这是输出。如果您了解DP,您可以看到它从列向后构建最佳路径
    import java.util.Arrays;
    
    public class MaxPath {
      public static void main(String[] args) {
        int[][] a = {
          {2, 3, 17},
          {4, 1, -1},
          {5, 0, 14}
        };
        System.out.println(new Dp(a).cost());
      }
    }
    
    class Dp {
      final int[][] a, c;
      final int m, n;
    
      Dp(int[][] a) {
        this.a = a;
        this.m = a.length;
        this.n = a[0].length;
        this.c = new int[2 * m - 2][m];
      }
    
      int cost() {
        Arrays.fill(c[fx(m - 1)], 0);
        for (int j = n - 1; j >= 0; j--) {
          // f = 0
          for (int i = 0; i < m; i++) {
            c[fx(0)][i] = a[i][j] + c[fx(m - 1)][i];
          }
          for (int f = 1; f < m - 1; f++) {
            for (int i = 0; i < m; i++) {
              c[fx(-f)][i] = max(c[fx(0)][i], a[i][j] + c[fx(1 - f)][ix(i - 1)]);
              c[fx(+f)][i] = max(c[fx(0)][i], a[i][j] + c[fx(f - 1)][ix(i + 1)]);
            }
          }
          // f = m-1
          for (int i = 0; i < m; i++) {
            c[fx(m - 1)][i] = max(c[fx(0)][i], 
                a[i][j] + c[fx(m - 2)][ix(i + 1)], 
                a[i][j] + c[fx(2 - m)][ix(i - 1)]);
          }
          System.out.println("j=" + j + ": " + Arrays.deepToString(c));
        }
        return max(c[fx(m - 1)]);
      }
      // Functions to account for negative f and wrapping of i indices of c.
      int ix(int i) { return (i + m) % m; }
      int fx(int f) { return f + m - 2; }
      static int max(int ... x) { return Arrays.stream(x).max().getAsInt(); }
    }
    
    j=2: [[31, 16, 14], [17, -1, 14], [17, 13, 31], [31, 30, 31]]
    j=1: [[34, 35, 31], [34, 31, 31], [34, 32, 34], [35, 35, 35]]
    j=0: [[42, 41, 44], [37, 39, 40], [41, 44, 42], [46, 46, 46]]
    46
    
    2  3  17  -3
    4  1  -1  15
    5  0  14  -2
    
    Third column:
    
     y' 0  1  2
    y 
    0   17 30 31
    1   30 -1 30
    2   31 30 14
    
     y' 0  1  2
    y 
    0   -3 12 10  + max(17,30,31)
    1   12 15 13  + max(30,-1,30)
    2   10 13 -2  + max(31,30,14)
    
           =
    
        28 43 41
        42 45 43
        41 44 29
    
    15 + (0,1) or (2,1) + (1,1)
    
    import java.util.Scanner;
    
    public class MatrixTraversal {
    
        static int[][] cost;
        static int m, n, maxCost = 0;
    
        public static void solve(int currRow, int currCol, int[][] isVisited, int currCost) {
    
            int upperRow, lowerRow, rightCol;
            isVisited[currRow][currCol] = 1;
    
            currCost += cost[currRow][currCol];             //total cost upto current position
    
            if( currCol == (n - 1)                          //if we have reached the last column in matrix
                && maxCost < currCost )                     //and present cost is greater than previous maximum cost
                maxCost = currCost;
    
            upperRow = ((currRow - 1) + m) % m;             //upper row value taking care of teleportation
            lowerRow = (currRow + 1) % m;                   //lower row value taking care of teleportation
            rightCol = currCol + 1;                         //right column value
    
            if( isVisited[upperRow][currCol] == 0 )     //if upper cell has not been visited
                solve(upperRow, currCol, isVisited, currCost);
    
            if( isVisited[lowerRow][currCol] == 0 )     //if lower cell has not been visited
                solve(lowerRow, currCol, isVisited, currCost);
    
            if( rightCol != n &&                            //if we are not at the last column of the matrix
                isVisited[currRow][rightCol] == 0 )     //and the right cell has not been visited
                solve(currRow, rightCol, isVisited, currCost);
    
            isVisited[currRow][currCol] = 0;
    
        }
    
        public static void main(String[] args) {
    
            int[][] isVisited;
            int i, j;
    
            Scanner sc = new Scanner(System.in);
    
            System.out.print("Enter the no.of rows(m): ");
            m = sc.nextInt();
    
            System.out.print("Enter the no.of columns(n): ");
            n = sc.nextInt();
    
            cost = new int[m][n];
            isVisited = new int[m][n];
    
            System.out.println("Enter the cost matrix:");
            for(i = 0; i < m; i++)
                for(j = 0; j < n; j++)
                    cost[i][j] = sc.nextInt();              //generating the cost matrix
    
            for(i = 0; i < m; i++)
                solve(i, 0, isVisited, 0);                  //finding maximum traversal cost starting from each cell in 1st column 
    
            System.out.println(maxCost);
    
        }
    
    }
    
    a = {{17, -3}
        ,{-1, 15}}
    
    17,-3
    17,-3,15
    17,-1,15
    17,-1,15,-3
    
    -1,15
    -1,15,-3
    -1,17,-3
    -1,17,-3,15
    
    a = {{17, -3}
        ,{-1, 15}}
    
    f(-1) -> max(15,15 - 3)
          -> 17 -> max(-3,-3 + 15) 
    
    f(17) -> max(-3,-3 + 15)
          -> -1 -> max(15,15 - 3) 
    
    a = {{17, -3}
        ,{-1, 15}}
    
    17
    16
    
    best exit at -3 = max(-3 + 17*, 15 - 3 + 16*) = 28
    best exit at 15 = max(15 + 16*, -3 + 15 + 17*) = 31