php中的矩阵排列问题

时间:2010-08-27 13:20:53

标签: php algorithm logic

我想知道这个问题的一些解决方案。

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

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

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

6 个答案:

答案 0 :(得分:7)

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

转到: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 :(得分: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");
            }
        }
    }
}

答案 2 :(得分:3)

在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 :(得分:3)

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

其他解决方案使用变量迭代地累积信息。我想尝试一种功能性解决方案,其中任何表格单元格的数量(或者任何数字的表格单元格)都可以在不重复任何其他表格单元格的情况下被识别。

这是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>

答案 4 :(得分:2)

在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();
      }
   }

答案 5 :(得分:1)

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

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

这可以非常容易地适应矩形网格(只需指定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>";
?>