我有一个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
答案 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)
。 我正在尝试改进它。
答案 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 ;
}