我刚刚出现在询问这个问题的采访中。
问题是:
我的矩阵如下:
3 3
0 1 -1
1 0 -1
1 1 1
第一行包含row numbers (n)
和column numbers (m)
。然后,下面是给定的矩阵,其中1
表示金币,-1
表示障碍物。
规则:
(0, 0)
到(n-1, m-1)
,然后再从(n-1, m-1)
到(0, 0)
。right
到down
时,我只能移动到(0, 0)
和(n-1, m-1)
,而从{回来时,我只能移动left
和up
(n-1, m-1)
至(0, 0)
。1
,那么我会拿起那块金币。同样,如果在路径上遇到1
时回来,我会捡起1
。(n-1, m-1)
处的值为-1
或不存在到(n-1, m-1)
的路径,则总金块数为0。问题是查找可以累积的最大金块数量。
我的方法:
在访谈期间,我推断出这些规则推断出,如果我们将(0, 0)
到(n-1, m-1)
以及从(n-1, m-1)
到(0, 0)
的规则合并,我们实际上,您将希望通过所有可能的方向(从上,右,下和左)到达(0, 0)
至(n-1, m-1)
。我要做的就是在使用这4条路径方向时算出最大数量1。
然后我想出了以下递归代码,该递归代码似乎并不高效,但是可以工作。
#include <bits/stdc++.h>
using namespace std;
int n, m;
int mat[100][100];
int lookup[100][100];
int getcount(int pgc, int r, int c) {
if(r == n-1 && c == m-1) {
if(mat[r][c] == -1) return 0;
else return mat[r][c] + pgc;
}
int cgc = mat[r][c];
int tmp1 = 0, tmp2 = 0, tmp3 = 0, tmp4 = 0;
if (((r + 1) < n) &&( mat[r + 1][c] != -1) && (lookup[r+1][c] != -1)) {
// go down
lookup[r + 1][c] = -1;
tmp1 = getcount(cgc + pgc, r + 1, c);
lookup[r + 1][c] = 0;
}
if (c + 1 < m && mat[r][c + 1] != -1 && lookup[r][c+1] != -1) {
// go right
lookup[r][c + 1] = -1;
tmp2 = getcount(cgc + pgc, r, c + 1);
lookup[r][c + 1] = 0;
}
if (r - 1 >= 0 && mat[r - 1][c] != -1 && lookup[r - 1][c] != -1) {
// go up
lookup[r - 1][c] = -1;
tmp3 = getcount(cgc + pgc, r - 1, c);
lookup[r - 1][c] = 0;
}
if (c - 1 >= 0 && mat[r][c - 1] != -1 && lookup[r][c-1] != -1) {
// go left
lookup[r][c - 1] = -1;
tmp4 = getcount(cgc + pgc, r, c - 1);
lookup[r][c - 1] = 0;
}
return max(tmp1, max(tmp2, max(tmp3, tmp4)));
}
int collectMax() {
int ans = 0;
if(mat[n-1][m-1] == -1 || mat[0][0] == -1) ans = 0;
else {
int r = 0, c = 0;
int gc = 0;
// if(mat[0][0] == 1) gc = 1;
ans = getcount(gc, r, c);
ans = max(0, ans);
}
return ans;
}
int main() {
cin>>n>>m;
for(int i = 0; i<n; i++) {
for(int j = 0; j<m; j++) {
cin>>mat[i][j];
}
}
cout<<collectMax()<<endl;
return 0;
}
如何使其高效?使用DP进行优化有范围吗?谢谢。
一些用于实践的测试用例:
输入1:
3 3
0 1 -1
1 0 -1
1 1 1
输出1:
5
输入2:
3 3
0 1 1
1 0 1
1 1 1
输出2:
7
输入3:
3 3
0 1 1
1 0 -1
1 1 -1
输出3:
0
答案 0 :(得分:2)
这在 O (min( m 2 n , mn 2 ))时间和 O (min( m 2 , n 2 ))空间使用动态编程。
该想法是考虑看起来像这样的斜条(粗体):
0 1 -1
1 0 -1
1 1 1
您的字符(=“您”,但我想区分您的程序在查找最佳路径中将做什么以及您的字符 em>会采用采取的最佳路径)将对每个这样的地带进行两次精确的访问:一次从(0,́0)到( m −1, > n −1),然后一次返回。这是因为每次合法移动都沿允许的方向从一个带移动到相邻带。
因此,对于每个条带,从(0,́0)的单元素带开始,到( m -1, n −1),您的程序将考虑该条带中的所有可能的元素对-称为它们( i 1 , j 1 )和( i 2 , j 2 )-并找到最大不同数量的黄金可以从(0,0)到( i 1 , j 1 )的路径上获得的硬币加上从( i 2 , j 2 )返回(0,0)的路径。对于每个试条,将结果存储在矩阵中,以便可以将其用于计算下一个试条的结果。 (完成试纸后,可以丢弃前一试纸的结果。)
特殊情况:
请确保区分不可能部分路径(其中( i 1 , j 1 )或( i 2 , j 2 )是障碍物,或只能通过不包含任何硬币的局部路径通过障碍物到达。否则,您会错误处理以下情况:
0 0 -1
0 -1 1
0 0 0
正确答案为0,因为实际上无法获得孤金币。