【问题标题】:Help with spiral matrix帮助螺旋矩阵
【发布时间】:2010-11-05 20:35:16
【问题描述】:

我需要为 Pascal 编写一个程序,使数组成为这样的螺旋形式:

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

从 1 开始,一直到 36,但这不是那么重要。

经过 3 天的思考,我不知道如何实现这一点。

问题不在于语言语法或数组,而在于算法。

你能帮我提供任何编程语言的想法、链接、伪代码或程序代码吗?

【问题讨论】:

标签: algorithm language-agnostic


【解决方案1】:

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

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

对于i1n/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

我希望我把这个想法说清楚了;有不明白的地方可以追问。

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

【讨论】:

    【解决方案2】:

    有一个很好的想法可以用来在遍历矩阵时改变方向。请看下表。输入 (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) 不可“填充”而无法再填充当前方向,请更改方向。

    【讨论】:

      【解决方案3】:

      最简单的想法是从螺旋的尽头开始,然后往回走。

      有四个变量(lefttoprightbottom)告诉您从每一侧适当地填充了多少。

      制作一个适当大小的矩阵。

      left = top = 0rightbottom 初始化为最后一列和最后一行的索引。

      • left 填充bottom 行 -> right。将bottom 减一。

      • bottom 填充right -> top。将right 减一。

      • right 填充top -> left。将top 加一。

      • top 填充left -> bottom。将left 加一。

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

      【讨论】:

        【解决方案4】:

        应用右手法则怎么样(比如解迷宫)。

        考虑一下你走后的每个牢房都变成了墙。

        【讨论】:

        • 这个提示更像是评论而不是答案。
        【解决方案5】:

        这是一个来自 Java 程序的 sn-p,用于执行螺旋矩阵访问。它跟踪方向的变化,以感知在任何给定方向旅行时还要进行多少次访问。简化此问题的模式是,在任何给定方向旅行时,下次您访问该方向时,访问次数会减少一次。更简单地说,如果您第一次沿水平方向旅行,您将进行 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 44 48

        【讨论】:

          【解决方案6】:

          到#1

          我写了程序,结果是这样的:

          00000
          10000
          11000
          11100
          .....
          

          我不知道,也许我没有理解你的算法或发生了任何其他问题。 这是代码:

            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】:

            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】:

              这是一个用 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

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

              【讨论】:

              • 再次为我向后思考:)。
              【解决方案9】:

              你的意思是它必须从左到右,从上到下打印数字吗?知道要生成平方数,将连续的奇数相加 - 1 + 3 + 5 + 7 + 9 + 11 = 36 会有所帮助。

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

              【讨论】:

                【解决方案10】:
                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();
                     }
                 }
                }
                

                你从左到右,然后向下。离开,重新开始。希望能帮助到你。 :)

                【讨论】:

                  猜你喜欢
                  • 2022-07-21
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2018-03-23
                  相关资源
                  最近更新 更多