从[0,0]到最后一行在矩阵中查找长度为N的最大成本路径的算法

时间:2012-10-05 10:35:27

标签: performance algorithm matrix

我有一个n*n矩阵,其中每个元素代表一个整数。从[0,0]开始,我必须找到确切m元素到最后一行的路径,并返回最高成本。路径可以在最后一行的任何列中结束,并n ≤ m ≤ n^2

我想找到从m[0,0]的所有长度为[n-1, 0], [n-1, 1] ... [n-1, n-1]的路径。但它感觉不是最佳...

哪种算法最有效的方法呢? BFS还是DFS?

修改

可能的方向是向下/向右/向左,但只能访问每个元素一次。

编辑2

因此,例如,如果给出了这个矩阵(n = 4):

[   1   4   1  20 ]
[   5   0   2   8 ]
[   6   8   3   8 ]
[   3   2   9   5 ]

并且m = 7,路径可以是

[   →   →   →   ↓ ]
[   5   0   2   ↓ ]
[   6   8   3   ↓ ]
[   3   2   9   x ] = Path cost = 47

[   ↓   4   1  20 ]
[   ↓   0   2   8 ]
[   →   →   ↓   8 ]
[   3   2   →   x ] = Path cost = 32 

m = n^2

[   →   →   →   ↓ ]
[   ↓   ←   ←   ← ]
[   →   →   →   ↓ ]
[   x   ←   ←   ← ]

编辑3 /解决方案

感谢WanderleyGuimarães,
http://ideone.com/0iLS2

4 个答案:

答案 0 :(得分:2)

您可以使用动态编程解决此问题。设value(i, j)矩阵位置(i, j)的值(第i行,第j列)。

if i <  0 then f(i, j) = 0
if i == 0 then f(i, j) = value(i, j)
if i >  0 then f(i, j) = max(f(i-1, j), f(i, j-1)) + value(i, j)

这种复发假设您在下台时使用矩阵中的位置。所以,你的答案是max(f(m, 0), f(m-1, 1), f(m - 2, 2), ..., f(1, m))

例如:

n = 4

提供以下矩阵
1 1 1 1
1 2 1 1
2 1 1 1
1 2 1 1

如果m = 2那么你就不能去第二行了。你回答的是f(2, 2) = 4

如果m = 4那么你就不能去第三行了。你回答的是f(3, 2) = 5

(我正在学习英语,所以如果你不理解某些东西让我知道,我会尽力改进我的解释。)

编辑::允许向下/向左/向右移动

您可以实施以下重复:

if i == n, j == n, p == m, j == 0 then f(i, j, p, d) = 0
if d == DOWN  then f(i, j, p, d) = max(f(i+1, j, p+1, DOWN), f(i, j-1, p+1, RIGHT),   f(i, j+1, p+1,LEFT)) + value(i, j)
if d == LEFT  then f(i, j, p, d) = max(f(i+1, j, p+1, DOWN), f(i, j+1, p+1, LEFT )) + value(i, j)
if d == RIGHT then f(i, j, p, d) = max(f(i+1, j, p+1, DOWN), f(i, j-1, p+1, RIGHT)) + value(i, j)

此解决方案为O(n^4)我正在尝试改进它。

您可以在http://ideone.com/tbH1j

进行测试

答案 1 :(得分:1)

这个问题非常有名。最有效的方法是动态编程。

dp[i][j]是从0,0来到i,j时的最大总和 然后,dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + matrix[i][j];

执行此操作后,请检查您可以去的每个位置值并获得最大值。

答案 2 :(得分:1)

这实际上是一个DAG,因此最长路径问题的动态编程解决方案有效。

为什么选择DAG?从两个水平相邻的顶点开始有一个明显的循环。如果你使用“明显的”图表,当然。

不太明显的方法是将其作为(顶点,方向)的图形重新设计,其中哪个方向是从下/左/右取的最后一个方向。向下方向的顶点可以向下,向左或向右,而向右方向的顶点只能向下/向右,向左方向的顶点只能向左/向下。该图显然是非循环的,它包含原始矩阵中的所有可能路径。

因此,忽略限制m,对(a,b,方向)最长路径的可能递归是

pdl[i][j] = max(pdl[i][j-1], pd[i-1][j])+arr[i][j];
pdr[i][j] = max(pdr[i][j+1], pd[i-1][j])+arr[i][j];
pd[i][j] = max(pdl[i][j], pdr[i][j]);

pd是“向下”顶点的数组,右侧为pdr,左侧为pdl。作为一个实现细节,请注意我在pdl中保持左边和相应下顶点的最大值,但这并不重要,因为任何具有方向“向下”的顶点都可以左右移动,就像“左边”一样“顶点会。与pdr相同。

限制意味着您必须为该DP解决方案添加另一个维度,也就是说,您必须保留pd[i][j][moves],这样可以保持最高总和,直到顶点(i,j)使用{{1}移动,获得递归

pdl[i][j][moves] = max(pdl[i][j-1][moves-1], pd[i-1][j][moves-1])+arr[i][j];
pdr[i][j][moves] = max(pdr[i][j+1][moves-1], pd[i-1][j][moves-1])+arr[i][j];
pd[i][j][moves] = max(pdl[i][j][moves-1], pdr[i][j][moves-1]);

答案 3 :(得分:-1)

此问题可以使用递归和回溯来解决。保持到目前为止所涵盖的步数以及到目前为止的路径成本。

以下是我的实施https://ideone.com/N6T55p

void fun_me(int arr[4][4], int m, int n,int i,int j,int steps,int cost)
{

//cout<<steps<<endl;
if(i>=n || j>=n)
    return;
visited[i][j]=1;
if(i==n-1 && steps==m-1)
{
    if(maxer<arr[i][j]+cost)
        maxer=arr[i][j]+cost;
    //cout<<arr[i][j]+cost<<endl;
}

if(isvalid(i+1,j,n) && !visited[i+1][j])
    fun_me(arr,m,n,i+1,j,steps+1,cost+arr[i][j]);

if(isvalid(i,j+1,n) && !visited[i][j+1])
    fun_me(arr,m,n,i,j+1,steps+1,cost+arr[i][j]);

if(isvalid(i,j-1,n) && !visited[i][j-1])
    fun_me(arr,m,n,i,j-1,steps+1,cost+arr[i][j]);

visited[i][j]=0;
return ;
}