打印zigtag矩阵

/**
 * 描述:打印zigzag矩阵
 *       0  1  5  6 14 15 27 28
 *       2  4  7 13 16 26 29 42
 *       3  8 12 17 25 30 41 43
 *       9 11 18 24 31 40 44 53
 *      10 19 23 32 39 45 52 54
 *      20 22 33 38 46 51 55 60
 *      21 34 37 47 50 56 59 61
 *      35 36 48 49 57 58 62 63
 * 
 * Date: 2011-08-08
 */


# include  <iostream >
# include  <iomanip >
using  namespace std;

int a[ 10][ 10];

void PrintZigzag( int n)
{
     int value  =  0;
     int i,j,k;
     int num;
     //上三角
     for (i = 0; i <n; i ++)
    {
        num  =  0;
         if ( 0  == i  %  2)
        { /*偶数*/
            j  = i;
            k  =  0;
             while (num ++  < = i)
            {
                a[j --][k ++= value ++;    
            }
        }
         else
        { /*奇数*/
            j  =  0;
            k  = i;
             while (num ++  < = i)
            {
                a[j ++][k --= value ++;    
            }    
        }
    }

     //下三角
     for (i  = n - 2; i  > =  0; i --)
    {
        num  =  0;
         if ( 0  == i  %  2)
        { /*偶数*/
            j  = n  -  1;
            k  = n  - 1  - i;
             while (num ++  < = i)
            {
                a[j --][k ++= value ++;    
            }
        }
         else
        { /*奇数*/
            j  = n  -  1  - i;
            k  = n  -  1;
             while (num ++  < = i)
            {
                a[j ++][k --= value ++;    
            }    
        }
    }

}

/**
 * test
 */

int main()
{
     int n, i, j;
    cin  >> n;
     for(i  =  0; i  < n; i ++)
    {
         for (j  =  0; j  < n; j ++)
        {
            a[i][j]  =  0;
        }
    }

    PrintZigzag(n);

     for(i  =  0; i  < n; i ++)
    {
         for (j  =  0; j  < n; j ++)
        {
            cout  << setw( 4<< a[i][j];
        }
        cout  << endl;
    }

     return  1;
}
 
方法虽蠢却易理解。
通过观察zigzag矩阵可发现几个特点:
  1. 左上三角(以对角线方向查看)个数从1递增至n(矩阵维数),右下三角从n-1递减至1。则可以将zigzag矩阵分为上三角和下三角两部分处理。
  2. 观察zigzag矩阵,以对角线方向计(行数从0开始计数),则偶数行规律是:从左到右;奇数行规律是:从右到左。则再分为奇偶行进行处理。
     



当然,有一种十分巧妙的方法如下。
# include  <stdio.h >
# include  <stdlib.h >

int main()
{
     int N;
     int s, i, j;
     int squa;
    scanf( "%d"&N);
     /* 分配空间 */
     int  * *= ( int  * *)malloc(N  *  sizeof( int  *));
     if(a  == NULL)
         return  0;
     for(i  =  0; i  < N; i ++
    {
         if((a[i]  = ( int  *)malloc(N  *  sizeof( int)))  == NULL) 
        {
             while( --i > = 0)
                free(a[i]);
            free(a);
             return  0;
        }
    }
     /* 数组赋值 */
    squa  = N *N;    
     for(i  =  0; i  < N; i ++)
         for(j  =  0; j  < N; j ++
        {
            s  = i  + j;
             if(s  < N)  /*上三角*/
            {
                 a[i][j] = s*(s+1)/2 + (((i+j)%2 == 0)? j : i);
            }
             else 
            {  /*下三角*/
                 s = (N-1-i) + (N-1-j);
                a[i][j] = squa - s*(s+1)/2 - (N - (((i+j)%2 == 0)? j : i));
            }
        }
     /* 打印输出 */    
     for(i  =  0; i  < N; i ++
    {
         for(j  =  0; j  < N; j ++)
        {
            printf( "%6d", a[i][j]);
        }
        printf( "\n");
    }
     return  1;
}
 
通过观察zigzag数组,可以发现,对角线上(i+j)为常数,记为s(s=i+j)。(i为行数,j为列数)
 
仍然是分为上三角和下三角两部分处理。
 
对于上三角,每一个斜线上的个数比上一行多一个。且,每个斜线上的第一个元素表示了该斜线之前元素的个数。运用等差数列求和公式,则每一斜线第一个元素的值为 (1 + (i+j)) * (i+j) / 2 = (1 + s) * s / 2
斜线中的任意元素可表示为s*(s+1)/2+i(此处来个奇偶判断就知道是加i还是加j了。)那么就不难理解代码中 a[i][j] = s*(s+1)/2 + (((i+j)%2 == 0)? j : i);的含义了。
 
对于下三角,斜线上元素的个数是递减的。反过来看可以看成是递增的,就仍然可以套用等差数列求和公式,求出剩下的元素的个数,用总元素个数减去剩下的元素个数就是当前斜线上的第一个元素值。

我们知道所有元素的个数是n*n,则该斜线的第一个元素值为n*n - s*(s+1)/2。此处的s就不是i+j了,而是(n-1-i)+(n-1-j)。这样也不难理解代码中s = (N-1-i) + (N-1-j);  a[i][j] = squa - s*(s+1)/2 - (N - (((i+j)%2 == 0)? j : i));两句的含义了。


转自:http://blog.163.com/yangjun1988422@126/blog/static/4741291720117842634276/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值