【问题标题】:Matrix arrangement issues in phpphp中的矩阵排列问题
【发布时间】:2011-04-04 19:34:09
【问题描述】:

我想知道此类问题的一些解决方案。

给定一个数字,比如说 16,你必须以这种方式排列一个矩阵

1  2  3  4
12 13 14 5
11 16 15 6
10 9  8  7

语言无关紧要,(最好是 PHP);

【问题讨论】:

  • 你得到的数字总是一个完美的正方形吗?
  • 先说是的,以后会看到其他情况。
  • 现在开学了,我看到很多“语言无关紧要”的问题:)
  • 我想之前有几个问题需要回答:矩阵应该总是 4x4 吗?还是序列总是从 1 开始,矩阵必须选得足够大?
  • 问题是否包括格式化输出以排列列,或者只是让数组具有正确的内容?

标签: php algorithm logic


【解决方案1】:

[编辑:更新] 如果语言无关紧要:

转至:http://rosettacode.org/wiki/Spiral_matrix


在 PHP 中:

给你:

<?php
function getSpiralArray($n)
{
    $pos = 0;
    $count = $n;
    $value = -$n;
    $sum = -1;

    do
    {
        $value = -1 * $value / $n;
        for ($i = 0; $i < $count; $i++)
        {
            $sum += $value;
            $result[$sum / $n][$sum % $n] = $pos++;
        }
        $value *= $n;
        $count--;
        for ($i = 0; $i < $count; $i++)
        {
            $sum += $value;
            $result[$sum / $n][$sum % $n] = $pos++;
        }
    } while ($count > 0);

    return $result;
}

function PrintArray($array)
{
    for ($i = 0; $i < count($array); $i++) {
        for ($j = 0; $j < count($array); $j++) {
            echo str_pad($array[$i][$j],3,' ');
        }
        echo '<br/>';
    }
}

$arr = getSpiralArray(4);
echo '<pre>';
PrintArray($arr);
echo '</pre>';
?>

【讨论】:

  • +1 有趣地使用 $value 作为描述当前方向的向量。无信息变量名称 $value, $count 的“虚拟”-1
  • 爱J ==> spiral =. ,~ $ [: /: }.@(2 # &gt;:@i.@-) +/\@# &lt;:@+: $ (, -)@(1&amp;,)
【解决方案2】:

在python中:

from numpy import *

def spiral(N):
    A = zeros((N,N), dtype='int')
    vx, vy = 0, 1 # current direction
    x, y = 0, -1 # current position
    c = 1
    Z = [N] # Z will contain the number of steps forward before changing direction
    for i in range(N-1, 0, -1):
        Z += [i, i]
    for i in range(len(Z)):
        for j in range(Z[i]):
            x += vx
            y += vy
            A[x, y] = c
            c += 1
        vx, vy = vy, -vx
    return A

print spiral(4)  

【讨论】:

    【解决方案3】:

    看起来蛇游戏可能会奏效。跟踪方向矢量,每次撞到边或人口稠密的正方形时向右转 90 度。尾巴无限延伸:)

    编辑:C# 中的 Snakey v0.1。也适用于非方形网格;)

    using System;
    using System.Text;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            public enum Direction
            {
                Up,
                Down,
                Left,
                Right
            }
    
            static void Main(string[] args)
            {
                int[,] maze;
    
                Direction currentDirection = Direction.Right;
    
                bool totallyStuck = false;
                bool complete = false;
                int currentX = 0;
                int currentY = 0;
                int boundX = 4;
                int boundY = 5;
                int currentNumber = 1;
                int stuckCounter = 0;
                bool placeNumber = true;
    
                maze = new int[boundY, boundX];
    
                while ((!totallyStuck) && (!complete))
                {
                    if (placeNumber)
                    {
                        maze[currentY, currentX] = currentNumber;
                        currentNumber++;
                        stuckCounter = 0;
                    }
    
                    switch (currentDirection)
                    {
                        case Direction.Right:
                            // Noted short Circuit Bool Evan
                            if ((currentX + 1 < boundX) && (maze[currentY, currentX + 1] == 0))
                            {
                                placeNumber = true;
                                currentX++;
                                stuckCounter = 0;
                            }
                            else
                            {
                                placeNumber = false;
                                stuckCounter++;
                            }
    
                            break;
                        case Direction.Left:
                            if ((currentX - 1 >= 0) && (maze[currentY, currentX - 1] == 0))
                            {
                                placeNumber = true;
                                currentX--;
                                stuckCounter = 0;
                            }
                            else
                            {
                                placeNumber = false;
                                stuckCounter++;
                            }
                            break;
                        case Direction.Down:
                            if ((currentY + 1 < boundY) && (maze[currentY + 1, currentX] == 0))
                            {
                                placeNumber = true;
                                currentY++;
                                stuckCounter = 0;
                            }
                            else
                            {
                                placeNumber = false;
                                stuckCounter++;
                            }
                            break;
                        case Direction.Up:
                            if ((currentY - 1 >= 0) && (maze[currentY - 1, currentX] == 0))
                            {
                                placeNumber = true;
                                currentY--;
                                stuckCounter = 0;
                            }
                            else
                            {
                                placeNumber = false;
                                stuckCounter++;
                            }
                            break;
                    }
    
                    // Is Snake stuck? If so, rotate 90 degs right
                    if (stuckCounter == 1)
                    {
                        switch (currentDirection)
                        {
                            case Direction.Right:
                                currentDirection = Direction.Down;
                                break;
                            case Direction.Down:
                                currentDirection = Direction.Left;
                                break;
                            case Direction.Left:
                                currentDirection = Direction.Up;
                                break;
                            case Direction.Up:
                                currentDirection = Direction.Right;
                                break;
                        }
                    }
                    else if (stuckCounter > 1)
                    {
                        totallyStuck = true;
                    }
                }
    
                // Draw final maze
                for (int y = 0; y < boundY; y++)
                {
                    for (int x = 0; x < boundX; x++)
                    {
                        Console.Write(string.Format("{0:00} ",maze[y, x]));
                    }
                    Console.Write("\r\n");
                }
            }
        }
    }
    

    【讨论】:

    • 这行不通。如果你从内部开始向外工作,你永远不会碰到一个被占领的广场。如果你从外面开始,在里面工作,你也永远不会碰到一个被占领的广场。如果你从一个空的网格开始,不管怎样,你都会一直走直线。
    • 除非您计算了您拥有的数字数量并根据该信息构建您的网格。
    • @meagar - o ye of little trust ;)
    【解决方案4】:

    好的,我只是为了好玩而发布这个答案。

    其他解决方案使用变量迭代地积累信息。我想尝试一个功能性解决方案,其中任何表格单元格的数量(或者,任何数字的表格单元格)都可以知道,而无需遍历任何其他单元格。

    这里是javascript。我知道,这不是纯粹的函数式编程,也不是非常优雅,但是每个表格单元格的数字计算是在不参考先前迭代的情况下完成的。所以它是多核友好的。

    现在我们只需要有人在 haskell 中完成它。 ;-)

    顺便说一句,这是在评论之前写的 1 应该在某个位置结束,不一定是西北角(目前仍未指定)。

    由于有人提到了 Ulam 螺旋,为了好玩,我添加了代码以在素数周围放置一个红色边框(即使螺旋是由内向外的)。有趣的是,似乎确实有素数的对角线条纹,尽管我不知道它是否与随机奇数的条纹有显着不同。

    代码:

    // http://stackoverflow.com/questions/3584557/logical-problem
    
    /* Return a square array initialized to the numbers 1...n2, arranged in a spiral */
    function spiralArray(n2) {
       var n = Math.round(Math.sqrt(n2));
       if (n * n != n2) {
          alert('' + n2 + ' is not a square.');
          return 0;
       }
       var h = n / 2;
       var arr = new Array(n);
       var i, j;
    
       for (i = 0; i < n; i++) {
          arr[i] = new Array(n);
          for (j = 0; j < n; j++) {
             // upper rows and lower rows of spiral already completed
             var ur = Math.min(i, n - i, j + 1, n - j, h),
                lr = Math.min(i, n - i - 1, j + 1, n - j - 1, h);
             // count of cells in completed rows
             // n + n-2 + n-4 ... n - 2*(ur-1) = ur*n - (ur*2*(ur - 1)/2) = ur * (n - ur + 1)
             // n-1 + n-3 + ... n-1 - 2*(lr-1) = lr*(n-1) - (lr*2*(lr - 1)/2) = lr * (n - 1 - lr + 1)
             var compr = ur * (n - ur + 1) + lr * (n - lr);
             // e.g. ur = 2, cr = 2*(5 - 2 + 1) = 2*4 = 8
             // left columns and right columns of spiral already completed
             var rc = Math.min(n - j - 1, i, n - i, j + 1, h),
                lc = Math.min(n - j - 1, i, n - i - 1, j, h);
             // count of cells in completed columns
             var compc = rc * (n - rc) + lc * (n - lc - 1);
             // offset along current row/column
             var offset;
             // Which direction are we going?
             if (ur > rc) {
                // going south
                offset = i - (n - j) + 1;
             } else if (rc > lr) {
                // going west
                offset = i - j;
             } else if (lr > lc) {
                // going north
                offset = n - i - 1 - j;
             } else {
                // going east
                offset = j - i + 1;
             }
    
             arr[i][j] = compr + compc + offset;
          }
       }
       return arr;
    }
    
    function isPrime(n) {
        // no fancy sieve... we're not going to be testing large primes.
        var lim = Math.floor(Math.sqrt(n));
        var i;
        if (n == 2) return true;
        else if (n == 1 || n % 2 == 0) return false;
        for (i = 3; i <= lim; i += 2) {
            if (n % i == 0) return false;
        }
        return true;
    }
    
    // display the given array as a table, with fancy background shading
    function writeArray(arr, tableId, m, n) {
       var tableElt = document.getElementById(tableId);
       var s = '<table align="right">';
       var scale = 1 / (m * n);
       var i, j;
       for (i = 0; i < m; i++) {
          s += '<tr>';
          for (j = 0; j < n; j++) {
             var border = isPrime(arr[i][j]) ? "border: solid red 1px;" : "";
             s += '<td style="' + border + '" >' + arr[i][j] + '</td>';
          }
          s += '</tr>';
       }
       s += '</table>';
    
       tableElt.innerHTML = s;
    }
    
    function tryIt(tableId) {
       var sizeElt = document.getElementById('size');
       var size = parseInt(sizeElt.value);
       writeArray(spiralArray(size * size), 'spiral', size, size);
    }
    

    执行它的 HTML 页面:

    <html>
        <head>
            <style type="text/css">
            td {
                text-align: right;
                font-weight: bold;
            }
            </style>
            <script type="text/javascript" src="so3584557.js" ></script>
        </head>
        <body>
            <form action="javascript:tryIt('spiral')">
                Size of spiral: <input type='text' id='size' />
            </form>
            <table id="spiral">
            </table>
        </body>
    </html>
    

    【讨论】:

      【解决方案5】:

      在java中

      
         public static void main(final String args[]) {
            int numbercnt = 16;
            int dim = (int) Math.sqrt(numbercnt);
            int[][] numbers = new int[dim][dim];
            ArrayList < Integer > ref = new ArrayList < Integer >();
            for (int i = 0; i < numbercnt; i++) {
               ref.add(i);
            }
            for (int i = 0; i < numbers.length; i++) {
               for (int j = 0; j < numbers[i].length; j++) {
                  int pos = (int) (Math.random() * ref.size());
                  numbers[j][i] = ref.get(pos);
                  ref.remove(pos);
               }
            }
            for (int i = 0; i < numbers.length; i++) {
               for (int j = 0; j < numbers[i].length; j++) {
                  System.out.print(numbers[j][i] + " ");
               }
               System.out.println();
            }
         }
      

      【讨论】:

      • 我认为 OP 不是在寻找随机排列的数字,而是在寻找螺旋。
      【解决方案6】:

      在 PHP 中,但使用递归。您可以通过指定边长来设置要填充的方框的大小。

      它的工作方式是函数最初在指定的数组位置填充值。然后它试图继续朝着它移动的方向移动。如果不能,则顺时针旋转 90 度。如果没有移动,它就会停止。这通过switch() 变量和递归的switch() 语句来处理。

      这可以很容易地适应矩形网格(只需为边长指定 2 个常数而不是 1 个)。

      Live Example with an 8x8 和你的4x4

      代码:

      <?php
      
        // Size of edge of matrix
      define("SIZE", 4);
      
        // Create empty array
      $array = array();
      
        // Fill array with a spiral.
      fillerUp($array);
      
      // Start at 0 / 0  and recurse
      function fillerUp(& $array, $x = 0, $y = 0, $count = 1, $direction = "right")
      {
            // Insert value
          $array[$x][$y] = $count;
      
            // Try to insert next value. Stop if matrix is full.
          switch ($direction)
          {
      
          case "right":        
              if (! $array[($x + 1) % SIZE][$y])
                  fillerUp($array, $x + 1, $y, ++$count, "right");
              elseif (! $array[$x][($y + 1) % SIZE])
                  fillerUp($array, $x, $y + 1, ++$count, "down");        
              break;
      
          case "down":  
              if (! $array[$x][($y + 1) % SIZE])
                  fillerUp($array, $x, $y + 1, ++$count, "down");
              elseif (! $array[($x - 1) % SIZE][$y])
                  fillerUp($array, $x - 1, $y, ++$count, "left");        
              break; 
      
          case "left":   
              if (! $array[abs(($x - 1) % SIZE)][$y])
                  fillerUp($array, $x - 1, $y, ++$count, "left");
              elseif (! $array[$x][abs(($y - 1) % SIZE)])
                  fillerUp($array, $x, $y - 1, ++$count, "up");        
              break;
      
          case "up":                   
              if (! $array[$x][abs(($y - 1) % SIZE)])
                  fillerUp($array, $x, $y - 1, ++$count, "up");        
              elseif (! $array[($x + 1) % SIZE][$y])
                  fillerUp($array, $x + 1, $y, ++$count, "right");            
              break; 
      
          }
      }
      
      // Show answer.
      echo "<pre>";
      for ($y = 0; $y < SIZE; ++$y)
      {
          for ($x = 0; $x < SIZE; ++$x)    
          {
              echo str_pad($array[$x][$y], 4, " ", STR_PAD_BOTH);
          }
          echo "\n";
      }
      echo "</pre>";
      ?>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-01-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多