一个人从网格的最左上角开始。网格的每个单元格是0,1,2,3,4,5,6或7.从任何单元格,如果此单元格为1,则只能进入右单元格,如果此单元格为2,则只能进入较低单元格,如果这个细胞是4,他只能去对角线对面的细胞,如果这个细胞是4,他可以去右下角细胞,如果这个细胞是5,他可以向右和对角线对着细胞,他可以去低如果这个细胞是7,那么如果这个细胞是6,那么他可以向右下方和对角线对着细胞,如果这个细胞是0,他就不能从这个细胞移动。
人想要去网格的最右边角落。你必须找到他可以到达目的地的路径数量。
输入:2D数组,行数,列数 输出:答案
我在PHP中的实现:
<?php
function process($a,$b, $m, $n, $i, $j) {
if($a[$i][$j]==1 || $a[$i][$j]==4 || $a[$i][$j]==5 || $a[$i][$j]==7)
if($j<$n-1)
$b[$i][$j+1]+=$b[$i][$j];
if($a[$i][$j]==2 || $a[$i][$j]==4 || $a[$i][$j]==6 || $a[$i][$j]==7)
if($i<$m-1)
$b[$i+1][$j]+=$b[$i][$j];
if($a[$i][$j]==3 || $a[$i][$j]==5 || $a[$i][$j]==6 || $a[$i][$j]==7)
if($j<$n-1 && $i<$m-1)
$b[$i+1][$j+1]+=$b[$i][$j];
return $b;
}
function no_of_path($a,$m,$n) {
$b=array();
for ($i = 0; $i < $m; $i++) {
$b1=array();
for($j=0;$j<$n;$j++) $b1[]=0;
$b[]=$b1;
}
$b[0][0]=1;
for ($i = 0; $i < min($m,$n); $i++) {
$b=process($a,$b,$m,$n,$i,$i);
for($j=$i+1;$j<$n;$j++)
$b=process($a,$b,$m,$n,$i,$j);
for($j=$i+1;$j<$m;$j++)
$b=process($a,$b,$m,$n,$j,$i);
}
return $b[$m-1][$n-1];
}
$a=array(
array(1,3,0,0,0,0),
array(0,0,4,5,1,0),
array(0,0,0,6,7,6),
array(0,0,0,0,5,0)
);
echo no_of_path($a,4,6);
?>
对于作为样本给出的输入。正确答案是我得到的3。但是当我试图提交时,它在很少的测试用例上给出了错误的答案。测试用例没有透露。谁能告诉我哪些测试用例会给出错误答案?如果有任何更好的实施建议?
答案 0 :(得分:3)
我确信你的算法是正确的,直到我要么挑战你对作业的正确理解,或者测试用例表明你的代码失败的正确性。
这就是我所做的。我写了一个使用递归的替代例程:
function no_of_path2($a, $i, $j, $m, $n) {
if ($i === $m-1 && $j === $n-1) {
return 1;
}
$count = 0;
if (($j < $n-1) && in_array($a[$i][$j], [1, 4, 5, 7])) {
$count += no_of_path2($a, $i, $j+1, $m, $n);
}
if (($i < $m-1) && in_array($a[$i][$j], [2, 4, 6, 7])) {
$count += no_of_path2($a, $i+1, $j, $m, $n);
}
if (($i < $m-1) && ($j < $n-1) && in_array($a[$i][$j], [3, 5, 6, 7])) {
$count += no_of_path2($a, $i+1, $j+1, $m, $n);
}
return $count;
}
因为它是递归使用的,你必须将它传递给&#34;当前&#34; element的行和列作为额外参数。
请注意,我没有尝试使此功能有效,即它不是动态编程的示例。为此,它应该存储结果并重新使用它们,就像使用$b
数组一样。这里的目的只是采用不同的方法,看看它是否会产生不同的结果。
然后我创建了两个实用程序函数:一个用随机值填充数组(0..7),另一个用于显示这样的数组:
function random_array($m, $n) {
$a = array();
for ($i = 0; $i < $m; $i++) {
$row = array();
for ($j = 0; $j < $n; $j++) {
$row[] = rand(0, 7);
}
$a[] = $row;
}
return $a;
}
function echo_array($a, $m, $n) {
for ($i = 0; $i < $m; $i++) {
for ($j = 0; $j < $n; $j++) {
echo $a[$i][$j];
}
echo "<br>";
}
}
最后,我将一个随机数组生成一个循环,并在每个迭代中调用你的函数和我的,比较结果:
$n = 3;
$m = 5;
for ($try = 1; $try < 10000; $try++) {
$a = random_array($m, $n);
$c1 = no_of_path($a,$m,$n);
$c2 = no_of_path2($a,0,0,$m,$n);
if ($c1 !== $c2) {
echo "difference found:", "<br>";
echo_array($a, $m, $n);
echo $c1, "<br>";
echo $c2, "<br>";
}
}
echo "done", "<br>";
我玩了一下行数和列数,还检查了边界情况,比如1行和1列。
结果是没有发现偏差。这两个函数为生成的所有案例提供相同数量的路径。
我采用第三种方法计算路径,使用电子表格中的公式,一个包含原始矩阵的表,以及一个包含中间计算和最终结果的表。在那里,我找不到你的功能的结果有任何差异。您可以在OpenDocument format或Excel format的Google文档中下载该电子表格。顺便说一下,是 动态编程的一个例子。
您在评论中表示,10%的未披露测试用例失败。因此,要么两个函数(和电子表格解决方案)都以相同的方式失败。这表明对原始作业的误解,或者测试用例假设错误答案。
关于您的代码的一些评论
您可以使用以下较短的代码初始化$b
数组:
$b = array_fill(0, $m, array_fill(0, $n, 0));
$b[0][0] = 1;
不是在单元格$a[$i][$i]
处开始每次迭代,而是从那里水平和垂直地进行,您可以逐行逐列遍历数组:
for ($i = 0; $i < $m; $i++)
for($j = 0; $j < $n; $j++)
$b = process($a, $b, $m, $n, $i, $j);
它会产生相同的结果。
10%测试失败的可能解释
我查看了数字的作用。下面的左表是您在问题中定义的,右表是看起来更对称的表:每列代表相应数字的一点,设置时答案是&#34;是&#34;:< / p>
+----------------------+ +----------------------+
| Can person move | | Alternative??? |
| Diag. | Down | Right | | Diag. | Down | Right |
+---+-------+------+-------+ +---+-------+------+-------+
| 0 | No | No | No | | 0 | No | No | No |
| 1 | No | No | Yes | | 1 | No | No | Yes |
| 2 | No | Yes | No | | 2 | No | Yes | No |
| 3 | Yes | No | No | | 3 | No | Yes | Yes |
| 4 | No | Yes | Yes | | 4 | Yes | No | No |
| 5 | Yes | No | Yes | | 5 | Yes | No | Yes |
| 6 | Yes | Yes | No | | 6 | Yes | Yes | No |
| 7 | Yes | Yes | Yes | | 7 | Yes | Yes | Yes |
+---+-------+------+-------+ +---+-------+------+-------+
两个表之间的唯一区别是数字3和4的角色是交换的。
使用上面列出的批量测试代码的修改版本,我将基于左表的算法结果与基于右表的相同算法进行了比较。结果是,大约13%的随机生成的6x4矩阵给出了不同的结果,而所有其他6x4矩阵产生了相同的结果。
这是否可以解释10%失败的测试用例?
答案 1 :(得分:-1)
这需要一个不错的动态编程解决方案,时间O(n ^ 2),空间也是O(n ^ 2)[我确信这可以优化为O(n),但是我们可以先关注算法]
假设矩阵是二维数组A [0..m-1,0..n-1] 对于0&lt; = i&lt; m,0&lt; = j&lt; n,假设D [i,j]是达到A [i,j]的方式的数量。由于存在八种不同的情况,最佳子结构公式将会很长:
D[i,j] = 0
// Count how many ways to reach A[i,j] from all possible sources
case-1: if A[i,j-1] == 1, D[i,j] += D[i,j-1]; // came by rule 1
case-2: if A[i-1,j] == 2, D[i,j] += D[i-1,j]; // came by rule 2
and so on, ....
also in A[i,j-1] check if j-1 is a valid index, i.e. j>0
我不能给出其余的规则,因为不清楚对角线对面的细胞意味着什么。你能发送问题页面的链接吗?