帮助螺旋矩阵

时间:2010-11-05 20:35:16

标签: algorithm language-agnostic

我需要为Pascal编写一个程序,它以如下的螺旋形式生成数组:

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

从1开始并继续到36但这不是那么重要。

经过3天的思考,我不知道如何实现这个目标。

问题不在于语言语法或数组,它只是在算法中。

您能用任何编程语言帮助我处理任何想法,链接,伪代码或程序代码吗?

10 个答案:

答案 0 :(得分:1)

考虑将nxn矩阵拆分为2x2,4x4,... nxn的同心子矩阵。在你的情况下,我们将有外部子矩阵(元素5到16)和内部子矩阵(元素1到4)。

现在,对于每个级别,您应该遍历四个边缘,并用所需的元素填充它们。你可以从里到外或从里到外。我会外出。我们保留一个最初为n*n的计数器(在我们的示例中为16)。

i1转到n/2

首先取下边缘(外层的元素16-13)。我们从x[n-i+1][i]转到x[n-i+1][n-i+1]并填写(第一级为16,15,14,13,第二级为4,3)

然后我们采取右边缘(外层的元素12-10)。我们从x[n-i][n-i+1]转到x[i][n-i+1](元素12,11,10为外层)。

然后我们采取上边缘(外层的元素9-7)。我们从x[i][n-i]转到x[i][i](外层的元素9,8,7)

最后我们采用左边缘(外层的元素6-5)。我们从x[i+1][i]转到x[n-i][i]并填充那一侧(外层为6,5)。

如果n是奇数,最后你会得到中间元素。然后,您所要做的就是分配x[n/2+1][n/2+1] = 1

我希望我明白这个想法;如果你有什么不明白的地方,请问。

我也没有实施解决方案,因为我认为你遇到的问题只是想法,而不是实现

答案 1 :(得分:1)

在迭代矩阵时,您可以使用一个很好的想法来改变方向。请看下表。输入(dX,dY)是增量值中的前一个方向,输出(cwdx,cwdy)是下一个顺时针方向,输出(ccwdx,ccwdy)是下一个逆时针方向(坐标(0,0))在左上角):

dx dy | cwdx cwdy | ccwdx ccwdy
-------------------------------
 1  0 |   0    1  |    0    -1
 0  1 |  -1    0  |    1     0
-1  0 |   0   -1  |    0     1
 0 -1 |   1    0  |   -1     0

因此,给定方向(dx,dy)顺时针转动你需要方向(-dy,dx),逆时针转动你需要方向(dx,-dy)。这意味着您不需要在代码中使用开关来转向,只需使用三行代码即可:

temp = dx; // this is for clockwise turn
dx = -dy;
dy = temp;

还有一个小技巧。要填充矩阵,您实际上可以从最后和最大数字开始,然后转到中心和数字1.如果从边缘开始并转到中心,那么您可以将数字填入一条直到可以(直到您到达矩阵的边缘或另一个数字)。如果由于(x + dx,y + dy)不能“填充”而无法填写当前方向,则改变方向。

答案 2 :(得分:1)

最简单的想法是从螺旋结束开始并继续前进。

有四个变量(lefttoprightbottom),可以告诉您从每一方面填充了多少。

制作适当大小的矩阵。

left = top = 0right以及bottom初始化为最后一列和行索引。

  • 填写bottom的{​​{1}}行 - > left。将right减少一个。

  • bottom填写right - > bottom。将top减少一个。

  • right填写top - > right。将left增加一个。

  • top填写left - > top。将bottom增加一个。

  • 迭代直到你填满整个矩阵。

答案 3 :(得分:1)

如何应用右手规则(就像解决迷宫一样)。

走完后,考虑每个牢房。

答案 4 :(得分:1)

这是Java程序执行螺旋矩阵访问的片段。它跟踪方向的变化,以感知在任何给定方向上行进时可以进行多少次访问。简化此问题的模式是,在任何指定方向上旅行时,下次访问该方向时,访问次数将减少一次。更简单地说,如果你第一次沿水平方向旅行,那么下次你在水平方向旅行时你将进行6次访问,你将进行5次访问。还应注意,水平和垂直访问是分开跟踪的。在需要改变方向之后,使用下面的单个等式来计算给定方向的访问次数。该等式通过从方向变化的总数中导出并使用mod作为选择器来选择垂直或水平。最后,考虑作为沿着矩阵移动的蛇的访问我将步骤/列的变化表示为速度(dy和dx)。正如另一个人指出的那样,可以使用一种模式,并用dy和dx的公式表示。

int[][] matrix = { {  1,  2,  3,  4,  5,  6,  7,  8 }, 
                   { 24, 25, 26, 27, 28, 29, 30,  9 },
                   { 23, 40, 41, 42, 43, 44, 31, 10 }, 
                   { 22, 39, 48, 47, 46, 45, 32, 11 },
                   { 21, 38, 37, 36, 35, 34, 33, 12 }, 
                   { 20, 19, 18, 17, 16, 15, 14, 13 } };

int n = matrix.length;
int m = matrix[0].length;
int row = 0;
int col = 0;
int dx = 1;
int dy = 0;
int dirChanges = 0;
int visits = m;

for (int i = 0; i < n * m; i++) {
  System.out.print(matrix[row][col] + " ");
  visits--;
  if (visits == 0) {
    visits = m * (dirChanges %2) + n * ((dirChanges + 1) %2) - (dirChanges/2 - 1);
    int temp = dx;
    dx = -dy;
    dy = temp;
    dirChanges++;
  }

  col += dx;
  row += dy;
}

该程序的输出是:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48

答案 5 :(得分:0)

这是一个用PHP编写的递归解决方案。

<?php
header('Content-type: text/plain');

function fill($x, $y, $dir, $leftInDir, $index, $stepSize, $stop){
    global $out;

    // set the value for the current item //
    $out[$y][$x] = $index;

    // everything that comes after this point is computing for the parameters of the next call //

    // activate this for debugging //
    //echo $x, ',', $y, ',', $dir, ',', $leftInDir, ',', $index, ',', $stepSize, ',', $stop, "\n";

    // decrease the number of steps left to take in the current direction //
    $leftInDir--;

    // check if this is the last item //
    if($index == $stop)
        return;

    // we're going up for the next item //
    if($dir == 'U')
        $y--;

    // we're going right for the next item //
    if($dir == 'R')
        $x++;

    // we're going down for the next item //
    if($dir == 'D')
        $y++;

    // we're going left for the next item //
    if($dir == 'L')
        $x--;

    // if this was the last step in this direction we need to change the direction //
    if($leftInDir == 0){

        // after two direction changes we need to increase the numbers of steps to take //
        if($dir == 'D' || $dir == 'U'){
            $stepSize++;
        }

        // update the direction clockwise //
        if($dir == 'U')
            $dir = 'R';
        else if($dir == 'R')
            $dir = 'D';
        else if($dir == 'D')
            $dir = 'L';
        else if($dir == 'L')
            $dir = 'U';

        // set the number of steps left as the step size //
        $leftInDir = $stepSize;
    }

    // increase the number to put in the cell //
    $index++;

    // call for the next item //
    fill($x,$y,$dir,$leftInDir,$index,$stepSize,$stop);
}

// set the size //
$size = 100;

// start the process from the center of the matrix //
fill((int)$size/2, (int)$size/2, 'R', 1, 1, 1, $size*$size);

// just output //
ksort($out);
foreach($out as $row){
    ksort($row);
    foreach($row as $item){
        echo str_pad($item, 7);
    }
    echo "\n";
}
?>

这个原则非常直接(好吧,不是直的,而是螺旋式,向前:))。你从1所在的地方开始,然后开始行走。 1右,1下,2左,2上,右3等,直至到达n*n

我把它写成递归函数,但它可以很容易地转换为循环。

答案 6 :(得分:0)

至#1

我编写了程序但结果如下:

00000
10000
11000
11100
.....

我不知道也许我没有理解你的algorythm或任何其他问题。 这是代码:

  n:=16;
  x:=1;
  For i:=1 to (n div 2) do
  begin
    For p:=i to n-i+1 do
    begin
      a[n-i+1,p]:=x;
    end;

    For q:=n-i to i do
    begin
      a[q,n-i+1]:=x;
    end;

    For o:=n-i to i do
    begin
      a[i,o]:=x;
    end;

    For u:=i+1 to n-i do
    begin
      a[u,i]:=x;
    end;
  end;

所以我尝试将#2程序从php编写为pascal并且它可以工作。 现在我将修复它顺时针写入数字并从数组中心开始。

非常感谢大家。

答案 7 :(得分:0)

CurValue = n * n;

终点是最左下点。

我们将从终点访问第一点(我们通过访问分配值)

每个单元格在开头都没有值。

x = n-1;

y = 0;

arr[x][y] = CurValue;


while ( CurValue greater than zero )
{


keep going right until you face a cell that has non-zero value or until you reach the most right cell

keep going top until you face a cell that has non-zero value or until you reach the most top cell

keep going left until you face a cell that has non-zero value or until you reach the most left cell

keep going down until you face a cell that has non-zero value or until you reach the most down cell

}

note: with each cell you visit then do the following :
    CurValue --;
    Assign CurValue to the current visited cell;

我希望上面的算法清楚明白。

答案 8 :(得分:0)

你的意思是它必须从左到右,从上到下打印出数字?有助于知道要制作正方形数字,可以将连续的奇数加在一起 ​​- 1 + 3 + 5 + 7 + 9 + 11 = 36。

在这个螺旋中,左边缘很简单......除了底行。因此,一种方法是编写算法,就好像螺旋是一个更大的循环,但不要打印出第一行以及第一列和最后一列。

答案 9 :(得分:0)

import java.util.Scanner; 
class CircularMatrixFromInnerClockwise
{
Scanner sc= new Scanner(System.in);
 void main()
 {
     System.out.println("Enter size.");
     int n=sc.nextInt();
     int a[][]= new int [n][n];
     int r1,c1,r2,c2;
     if(n%2==0)
     {
      r1=n/2-1;
      c1=n/2-1;
      r2=n/2-1;
      c2=n/2-1;
    }
    else
    {
      r1=(n+1)/2-1;
      c1=(n+1)/2-1;
      r2=(n+1)/2-1;
      c2=(n+1)/2-1;
    }
     int k=1;
     do
     {   
         if(c2<n-1&&r2<n-1)
        {
         r2++;
         c2++;
        }
        for(int i=c1;i<=c2;i++)
         a[r1][i]=k++;  
          if(k>=n*n)
         break;
        for(int i=r1+1;i<=r2;i++)
         a[i][c2]=k++; 
         if(k>=n*n)
         break;
        if(c1>0&&r1>0)
        {
             c1--;
             r1--;
        }
         for(int i=c2-1;i>=c1;i--)
         a[r2][i]=k++;
         if(k>=n*n)
         break;

         for(int i=r2-1;i>=r1+1;i--)
         a[i][c1]=k++;
         if(k>=n*n)
         break;
     }while(k<=n*n);
     System.out.println("Circular matrix");
     for(int i=0;i<n;i++)
     {
         for(int j=0;j<n;j++)
         {
             System.out.print( a[i][j]+"\t");
         }
         System.out.println();
     }
 }
}

你是从左到右,然后是下来。左,上,又一遍。希望能帮助到你。 :)