Java 基于动态规划的矩阵最大遍历代价
假设我有一个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
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[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