蛇形填数 关于循环的灵活使用


在n*n方针中填入1,2,3,……,n*n,要求填成蛇形,例如n=4时方阵为:

10  11  12  1

  9  16  13  2

  8  15  14  3

  7    6    5  4

类比数学中的矩阵,我们可以用一个二维数组来储存题目中的方阵。只要声明一个int A[N][N],就可以获得一个

大小为N*N的方阵。在声明时,可以让两个维度的大小不同,所以也可以声明成int A[M][N]这样的数组。


让我们从1开始依次填写,设填写的位置"笔"的坐标为(x,y),则一开始x=0,y=n-1,即第0行,第n-1列。笔的

轨迹为:下,下,下,左,左,左,上,上,右,右,下,下,左,上。总之,先是下,到不能填了为止,

然后依次是左,上,右,这个循环顺序始终不变。“不能填”是指再走就出界。或者再走就要走到了以前填过的

格子。如果我们把所有格子初始化为0,就能很方便地加以判断

程序实现如下:


#include <iostream>
using namespace std;
#define N 30
int main()
{  int n;
    cin>>n;
    int a[N][N]={0};    //将数组内所有数字置0,作为以后判断循环的条件
   int x,y;
    x=0;y=n-1;
    a[x][y]=1;         //初始化位置 此时数组的右上角为1
    int Count=1;       //计数器
    while( Count< n*n )//第一个循环:直到输入了n*n次后跳出
    {   //由于移动方向固定为顺时针,所以以下,左,右,上为一个循环
        while ( x+1< n && a[x+1][y]==0 )  //让所填的位置不断向下走
            a[++x][y]=++Count;            //遇到越界的情况就转弯
        while ( y-1>=0 && a[x][y-1]==0 )  //向左走
            a[x][--y]=++Count;
        while ( x-1>=0 && a[x-1][y]==0 )  //向上走
            a[--x][y]=++Count;
        while ( y+1< n && a[x][y+1]==0 )  //向右走
            a[x][++y]=++Count;
        //后一个条件来判断相应的位置是否有填过数字,如果有就转弯
    }
    for ( x=0 ; x<=n-1 ; x++)
    {   for(y=0 ; y<=n-1 ;y++ )
            cout<<a[x][y]<<"\t";
        cout<<endl;
    }
return 0;
}

四条while语句有点难懂,不过十分相似。因此只要介绍其中的第一条:不断向下走,并且填数。我们的原则是:

先判断,再移动,而不是走一步以后发现越界了在退回来。因此。我们要先进行预判,即是否越界。以及如果

继续走会不会碰到填过的格子。越界只要判断 x+1<n ,因为y的值没有修改,下一个格子是(x+1,y),因此只需

a[x+1][y]==0,简写成 !a[x+1][y] 。


在很多情况下,最好是在做一件事之前检查是不是可以做,而不要做完再后悔。因为“悔棋”往往比较麻烦。


不知道你有没有发现,这里有一个潜在的bug,如果越界,x+1会等于n,即a[x+1][y]将访问非法内存!



你可能感兴趣的:(ACM,OJ,南华大学)