在矩阵中查找4个方向的最高乘积

时间:2018-05-07 09:34:04

标签: php algorithm matrix

我遇到了这个挑战,要找到20x20 matrix of integers上连续4个数字的最高产品。

从由空格分隔的文件中逐行读取数字。

产品可以是水平,垂直和两个方向的对角线

我的“解决方案”给出了错误的答案。

编辑:我已经更新了代码,无需文件输入和添加样本数据;还修复了我在评论中指出的一个错误

$data = [
    [89,32,92,64,81,2,20,33,44,1,70,75,39,62,76,35,16,77,22,27],
    [53,11,6,95,41,51,31,59,8,23,19,13,61,91,48,69,84,52,66,24],
    [93,72,85,97,21,79,56,5,45,3,65,30,83,87,43,7,34,0,4,14],
    [29,17,49,9,82,90,55,67,15,63,54,94,12,28,96,37,58,98,86,78],
    [74,40,50,60,26,99,80,18,10,46,36,68,25,57,47,71,42,73,88,38],
    [50,22,6,26,18,53,52,5,46,2,89,77,83,48,4,58,45,28,84,81],
    [49,82,31,14,69,17,91,54,34,40,0,33,30,95,60,44,29,24,85,16],
    [27,11,76,39,15,86,92,74,99,59,94,12,55,57,38,96,47,32,78,75],
    [51,20,87,42,62,41,7,35,23,21,71,25,67,97,80,90,88,64,13,70],
    [19,9,56,43,68,93,65,98,36,3,61,63,10,72,8,73,1,66,79,37],
    [22,58,52,12,3,41,28,72,42,74,76,64,59,35,85,78,14,27,53,88],
    [46,80,5,96,7,68,61,69,67,34,36,40,82,26,75,50,29,91,10,2],
    [30,39,19,48,33,93,1,45,66,98,0,23,62,25,51,71,56,77,24,21],
    [79,87,94,60,8,32,13,65,4,92,73,9,31,37,17,84,15,90,86,20],
    [95,6,81,70,47,16,44,83,49,43,55,54,18,63,38,11,97,89,99,57],
    [95,78,64,58,7,17,53,28,74,86,6,12,54,85,21,94,16,69,25,68],
    [13,20,41,97,1,2,80,30,0,84,67,45,93,96,82,92,62,33,18,44],
    [60,77,31,70,76,36,59,38,15,3,91,46,65,73,49,11,8,35,5,52],
    [61,66,79,40,26,72,89,71,75,99,22,9,43,32,14,81,98,88,87,83],
    [10,4,23,19,56,57,51,47,50,27,90,63,42,29,24,55,48,37,39,34]
];

$matrix = [];
//maximums in possible directions
$maxes  = [0, 0, 0, 0];

//while ($line = trim(fgets(STDIN))) { 
while ($line = current($data)) {
    //the horizontal maxes can be calculated while loading
    //$array = explode(" ", $line);
    $array = $line;

    $hMax = array_product(array_slice($array, 0, 4));

    for ($i = 1; $i < (count($array)-4); $i++) {
        $max = array_product(array_slice($array, $i, 4));

        if($max > $hMax) {
            $hMax = $max;
        }
    }

    if ( $hMax > $maxes[0] ) {
        $maxes[0] = $hMax;
    }

    $matrix[] = $array;
    next($data);
}

// the last 3 rows can be skipped
for($i = 0; $i < (count($matrix)-4); $i++) {
    for ($j = 0; $j < (count($matrix[$i])-1); $j++) {

        $vMax  = 1;   // vertical
        $dlMax = 1;   // diagonal left
        $drMax = 1;   // diagonal rigth

        for ($k = 0; $k < 5; $k++) {
            $vMax  *= $matrix[$i + $k][$j];

            if ( $j < (count($matrix[$i]) - 4) ) {
                $drMax *= $matrix[$i + $k][$j + $k];
            }

            if ( $j > 3 ) {
                $dlMax *= $matrix[$i + $k][$j - $k];
            }
        }

        if ( $maxes[1] < $vMax )  $maxes[1] = $vMax;  // the index used to be 1 - my first mistake
        if ( $maxes[2] < $dlMax ) $maxes[2] = $dlMax; // the index used to be 1 - my first mistake
        if ( $maxes[3] < $drMax ) $maxes[3] = $drMax; // the index used to be 1 - my first mistake
    }
}

sort($maxes);
echo end($maxes).PHP_EOL;

我的方法在哪里出错了,怎么加速? 是否有任何可以应用的数学技巧(besides checking for zeros)?

编辑:代码为当前数据提供的解决方案4912231320是否正确?

2 个答案:

答案 0 :(得分:1)

我发现了2个主要错误,现在结果似乎合理67352832

我认为它是因为这个原因而解决的,但如果有人想出一些简化或加快速度的数学技巧,我会放弃接受的答案。

第一个错误是 for ($k = 0; $k < 5; $k++) {

它应该是 for ($k = 0; $k < 4; $k++) {

因为我们一次只计算4个数字,这就是为什么结果与10 ^ 8相比如此之大

第二个是 if ( $j > 3 ) {

应该是什么 if ( $j > 2 ) {

现在将包括一个更多的对角线可能性

答案 1 :(得分:1)

我们可以考虑四个方向,最底层或最右边的细胞可以是序列中的最后一个。如果m[i][j][k][d]是来自方向k的长度为d的序列的最高总数,则:

m[i][j][1][d] = data[i][j] for all d

m[i][j][k]['E'] = data[i][j] * m[i][j - 1][k - 1]['E']
m[i][j][k]['NE'] = data[i][j] * m[i - 1][j - 1][k - 1]['NE']
m[i][j][k]['N'] = data[i][j] * m[i - 1][j][k - 1]['N']
m[i][j][k]['NW'] = data[i][j] * m[i - 1][j + 1][k - 1]['NW']

如果我们从北到南,从东到西,我们已经计算了所需的细胞,显然,我们正在寻找

max(m[i][j][4][d])
  for all i, j, d