打印zigzag矩阵

/**
 * 描述:打印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[100][100];

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开始计数),则偶数行规律是:从左到右;奇数行规律是:从右到左。则再分为奇偶行进行处理。
因此,编程中:
     1. (i,j)是否在右下三角的判断标准是i+j > N;
     2. 按照斜行处理。

当然,有一种十分巧妙的方法如下。

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int N;
    int s, i, j;
    int squa;
    scanf("%d", &N);
    /* 分配空间 */
    int **a = (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/

posted @ 2012-05-03 15:45  wangicter的博客  阅读(520)  评论(0编辑  收藏  举报