计算m * n矩阵从左上角到右下角的所有可能路径

时间:2015-12-11 18:55:53

标签: php algorithm permutation

一个人从网格的最左上角开始。网格的每个单元格是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。但是当我试图提交时,它在很少的测试用例上给出了错误的答案。测试用例没有透露。谁能告诉我哪些测试用例会给出错误答案?如果有任何更好的实施建议?

2 个答案:

答案 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 formatExcel 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

我不能给出其余的规则,因为不清楚对角线对面的细胞意味着什么。你能发送问题页面的链接吗?