例27        回旋方阵

问题描述

编写程序,生成从内到外是连续的自然数排列的回旋方阵。例如,当n=3和n=4时的回旋方阵如下图1所示。

图1  由内到外回旋方阵

输入格式

一个正整数n(1≤n≤20)。

输出格式

N阶满足要求的由内到外回旋方阵。输出时共n行,每行n个数,每个数占4列。

输入样例

5

输出样例

21  20  19  18  17

22   7   6   5  16

23   8   1   4  15

24   9   2   3  14

25  10  11  12  13

(1)编程思路1。

观察图1及样例,由内到外回旋方阵的构造方法是:先将1填入方阵的中心位置(即i=(n-1)/2;  j=(n-1)/2;  a[i][j]=1),然后其余数的填写可以看成由向下填充(列号不变、行号加1,即i++)、向右填充(行号不变、列号加1,即j++)、向上填充(行号减1、列号不变,即i--)和向左填充(行号不变、列号减1,即j--)四个子过程不断交替完成的。

例如,图1所示的4阶由内到外回旋方阵可以看成由向下填充(2)、向右填充(3)、向上填充(4、5)、向左填充(6、7)、向下填充(8、9、10)、向右填充(11、12、13)、向上填充(14、15、16)这7个子过程完成的。

n阶由内到外回旋方阵可以看成由4个子过程交替进行来完成的,这4个子过程依次为向下填充、向右填充、向上填充、向左填充,用变量d来表示,其取值为1、2、3或4,1表示向下填充,2表示向右填充,3表示向上填充,4表示向左填充。每个子过程结束后,切换填充方向,方式为:d++,若d>4,d=1。

在这一序列子过程中,第1、2子过程填写1个数,第3、4子过程填写2个数,第5、6子过程填写3个数,第7、8子过程填写4个数,…,直到最后一个数n2填写完毕。

(2)源程序1。

#include<stdio.h>

int main()

{

int a[20][20]={0},i,j,k=1,n,x,d,cnt;

scanf("%d",&n);

i=(n-1)/2;  j=(n-1)/2;

a[i][j]=k++;

d=1;cnt=1;x=0;

while (k<=n*n)

{

switch (d)

{

case 1:i++;

a[i][j]=k++;

x++;

if (x==cnt)

d=2,x=0;

break;

case 2:j++;

a[i][j]=k++;

x++;

if (x==cnt)

d=3,x=0,cnt++;

break;

case 3:i--;

a[i][j]=k++;

x++;

if (x==cnt)

d=4,x=0;

break;

case 4:j--;

a[i][j]=k++;

x++;

if (x==cnt)

d=1,x=0,cnt++;

break;

}

}

for (i=0;i<n;i++)

{

for (j=0;j<n;j++)

printf("%4d",a[i][j]);

printf("\n");

}

return 0;

}

(3)编程思路2。

观察1所示的由内到外回旋方阵,可以看出,n阶由内到外回旋方阵可以看成是自然数n*n~1由外向内递减填充数字而构造成。

构造时,奇数阶方阵从左下角开始(即row=n-1、col=0),循环经过向上填充、向右填充、向下填充和向左填充的过程,直到全部数字填充完毕;偶数阶方阵从右上角开始(即row=0、col=n-1),循环经过向下填充、向左填充、向上填充和向右填充的过程,直到全部数字填充完毕。由于奇数阶和偶数阶填充顺序有差异,定义一个变量s作为标志,s==1时,表示进行向下填充和向左填充;s==-1表示进行向上填充和向右填充。奇数阶构造时,s初值为-1;偶数阶时为1。

为了清楚地标记出每次填充结束的位置,定义x1、x2、y1和y2这四个变量来分别保存向上、向下、向左和向右填充的边界。初始时, x1=0、y1=0、x2=n、y2=n。

例如,向上填充时,循环过程为

while(row>=x1)            //  向上填充

{

a[row][col]=num;

row--;             // 行号减1、列号不变,向上填充

num--;

}

一次向上填充结束后,x1加1(即x1++),这样向上填充的上边界增大了,下次就会少填一行。 同时修改row和col,即row--、col--,从而得到向左填充的起点。

由于奇数阶方阵先向上填充,这样当向左填充时,最底行的左下角已经填有数字,因此,向左填充的边界的初始值应为1(即y1=1)。同理,偶数阶方阵的初始向右填充的边界y2=n-1。

(4)源程序2。

#include<stdio.h>

int main()

{

int row,col,a[20][20]={0},n,num;

int x1,x2,y1,y2,s;

//  x1:填充上边界   x2:填充下边界

//  y1:填充左边界   y2:填充右边界

//  s:数组元素升降标记,s等于l为升,s等于-1为降

scanf("%d",&n);

num=n*n;

x1=0;  y1=0; x2=n; y2=n;

if (n%2==0)   { row=0;col=n-1;  y2=n-1; s=1;}

else      { row=n-1; col=0;  y1=1; s=-1;}

while (num>=1)

{

if(s==1)

{

while (row<x2)      // 向下填充

{  a[row][col]=num--;row++;  }

row--;  col--;       // 得到向左填充的起点

x2--;              // 向下填充的下边界缩小

while (col>=y1)     // 向左填充

{ a[row][col]=num--;col--; }

col++;     row--;   // 得到向上填充的起点

y1++;              // 向左填充的左边界增大

s=-1;              // 切换升降标志

}

else

{

while(row>=x1)    //  向上填充

{ a[row][col]=num--;  row--; }

row++;    col++;  //  得到向右填充的起点

x1++;             //  向上填充的上边界增大

while (col<y2)      //  向右填充

{a[row][col]=num--;col++;}

col--;    row++;    // 得到向下填充的起点

y2--;              //  向右填充的右边界缩小

s=1;              //  切换升降标志

}

}

for (int i=0;i<n;i++)

{

for (int j=0;j<n;j++)

printf("%4d",a[i][j]);

printf("\n");

}

return 0;

}

习题27

27-1  由外向内回旋方阵

问题描述

编写程序,生成从外到内是连续的自然数排列的回旋方阵。例如,当n=3和n=4时的回旋方阵如下图2所示。

图2  由外向内回旋方阵

输入格式

一个正整数n(1≤n≤20)。

输出格式

N阶满足要求的由外向内回旋方阵。输出时共n行,每行n个数,每个数占4列。

输入样例

5

输出样例

1  16  15  14  13

2  17  24  23  12

3  18  25  22  11

4  19  20  21  10

5   6   7   8   9

(1)编程思路。

由外向内回旋方阵可以通过对方阵的每一圈的各边的各个元素顺序赋值来完成。每一圈的赋值又依次包含4个顺序的过程。

1)一圈的左列从上至下递增赋值,一直赋值到超过最底行(即row==n)或下一位置已经赋值了(即a[row+1][col]!=0)。

while(row+1<n && !a[row+1][col])

a[++row][col]=++num;      // 列号col不变,行号row递增,数num递增

2)一圈的下行从左至右递增赋值,一直赋值到超过最右列(即col==n)或下一位置已经赋值了(即a[row][col+1]!=0)。

while(col+1<n&&!a[row][col+1])

a[row][++col]=++num;     // 行号row不变,列号col递增,数num递增

3)一圈的右列从下至上递增赋值,一直赋值到超过最顶列(即row==-1)或下一位置已经赋值了(即a[row-1][col]!=0)。

while(row-1>=0&&!a[row-1][col])

a[--row][col]=++num;     // 行号row递减,列号col不变,数num递增

4)一圈的上行从右至左递增赋值,一直赋值到超过最左列(即col==-1)或下一位置已经赋值了(即a[row][col-1]!=0)。

while(col-1>=0&&!a[row][col-1])

a[row][--col]=++num;     // 行号row不变,列号col递减,数num递增

初始时,row=0、col=0、num=1。

(2)源程序。

#include<stdio.h>

int main()

{

int a[20][20]={0};

int n,row,col,num=0;

scanf("%d",&n);

num=a[row=0][col=0]=1;               // 第0行第0列输入起始1

while(num<n*n)                      // 数组中的数不超过n*n

{

while(row+1<n && !a[row+1][col])  // 向下填充

a[++row][col]=++num;

while(col+1<n&&!a[row][col+1])    // 向右填充

a[row][++col]=++num;

while(row-1>=0&&!a[row-1][col])   // 向上填充

a[--row][col]=++num;

while(col-1>=0&&!a[row][col-1])    // 向左填充

a[row][--col]=++num;

}

for (int i=0;i<n;i++)

{

for (int j=0;j<n;j++)

printf("%4d",a[i][j]);

printf("\n");

}

return 0;

}

27-2  间断折叠方阵

问题描述

n阶间断折叠方阵是把从起始数1开始的n2个整数折叠为n行n列的n阶方阵:起始数1置于方阵的左上角,然后从起始数开始递增,每一层从第1行开始,先竖向下再折转向左,层层折叠地排列为间断折叠方阵。

例如,当n=4和n=5时的间断折叠方阵如下图3所示。

图3  间断折叠方阵

输入格式

一个正整数n(1≤n≤20)。

输出格式

N阶满足要求的间断折叠方阵。输出时共n行,每行n个数,每个数占4列。

输入样例

5

输出样例

1   2   5  10  17

4   3   6  11  18

9   8   7  12  19

16  15  14  13  20

25  24  23  22  21

(1)编程思路。

定义一个二维数组a保存方阵的各元素,从给定的起始数1开始,按递增1取值,根据间断折叠方阵的构造特点给二维数组a[n][n]赋值。

起始数1赋值给a[0][0]。

除a[0][0]外,n阶方阵还有叠折的n-1层:

第i层(i=1、2、…、n-1)的起始位置为(0,i),随后列号col不变行号row递增(即向下填写),至row=i时折转;转折后,行号row不变列号col递减(即向左填写),至col=0时该层结束,在每一位置分别按递增值赋值给a[row][col]。

具体过程描述为:

a[0][0]=1;

num=2;

for(i=1;i<m;i++)                          // 方阵共m层

{

row=0;  col=i;                           // 确定每层起始位置

a[row][col]= num++;

while(row<i)  a[++row][col]=num++;   // 先向下填

while(col>0)  a[row][--col]=num++;    // 再向左填

}

(2)源程序。

#include<stdio.h>

int main()

{

int i,m,num,row,col,a[20][20];

scanf("%d",&m);

a[0][0]=1;

num=2;

for (i=1;i<m;i++)   // 方阵共m层

{

row=0;  col=i;

a[row][col]=num++;

while(row<i)  a[++row][col]=num++;

while(col>0)  a[row][--col]=num++;

}

for (i=0;i<m;i++)

{

for (int j=0;j<m;j++)

printf("%4d",a[i][j]);

printf("\n");

}

return 0;

}

27-3 回转折叠方阵

问题描述

n阶回转折叠方阵是把起始数1置于方阵的左上角,然后从起始数开始递增,偶数层从第1行开始,先竖向下再折转向左;奇数层从第1列开始,先横向右再竖向上,呈首尾连接,层层折叠地排列为回转折叠方阵。例如,当n=4和n=5时的回转折叠方阵如下图4所示。

图4  回转折叠方阵

输入格式

一个正整数n(1≤n≤20)。

输出格式

N阶满足要求的回转折叠方阵。输出时共n行,每行n个数,每个数占4列。

输入样例

5

输出样例

1   2   9  10  25

4   3   8  11  24

5   6   7  12  23

16  15  14  13  22

17  18  19  20  21

(1)编程思路。

回转折叠方阵构造过程的奇数层(注意:由于数组下标从0开始,因此程序中层号也从0开始)与间断折叠构造过程相同,偶数层构造方法改变为:该层的起始位置为(i,0),随后行号row不变列号col递增(即向右填写),至col=i时折转;转折后,列号col不变行号row递减(即向上填写),至row=0时该层结束,在每一位置分别按递增值赋值给a[row][col]。具体描述为:

if (i%2==0)

{

row=i;col=0;                     // 确定偶数层的起始位置

a[row][col]=num++;

while(col<i) a[row][++col]=num++;  // 先向右填

while(row>0) a[--row][col]=num++;  // 再向上填

}

(2)源程序。

#include<stdio.h>

int main()

{

int i,m,num,row,col,a[20][20];

scanf("%d",&m);

a[0][0]=1;

num=2;

for(i=1;i<m;i++)   // 方阵共m层

{

if (i%2==1)

{

row=0;  col=i;

a[row][col]=num++;

while(row<i)  a[++row][col]=num++;

while(col>0)  a[row][--col]=num++;

}

else

{

row=i;col=0;

a[row][col]=num++;

while(col<i) a[row][++col]=num++;

while(row>0) a[--row][col]=num++;

}

}

for (i=0;i<m;i++)

{

for (int j=0;j<m;j++)

printf("%4d",a[i][j]);

printf("\n");

}

return 0;

}

C语言程序设计100例之(27):回旋方阵的更多相关文章

  1. 黑马程序员——经典C语言程序设计100例

    1.数字排列 2.奖金分配问题 3.已知条件求解整数 4.输入日期判断第几天 5.输入整数进行排序 6.用*号显示字母C的图案 7.显示特殊图案 8.打印九九口诀 9.输出国际象棋棋盘 10.打印楼梯 ...

  2. C语言程序设计100例之(9):生理周期

    例9    生理周期 问题描述 人生来就有三个生理周期,分别为体力.感情和智力周期,它们的周期长度为 23 天.28 天和33 天.每一个周期中有一天是高峰.在高峰这天,人会在相应的方面表现出色.例如 ...

  3. C语言程序设计100例之(14):丑数

    例14   丑数 问题描述 丑数是其质因子只可能是2,3或5的数.前10个丑数分别为1, 2, 3, 4, 5, 6, 8, 9, 10, 12.输入一个正整数n,求第n个丑数. 输入格式 每行为一个 ...

  4. C语言程序设计100例之(22):插入排序

    例22  插入排序 问题描述 排序是计算机程序设计中的一种重要操作,它的功能是将一个数据元素或记录的任意序列,重新排列成一个以关键字递增(或递减)排列的有序序列. 排序的方法有很多,简单插入排序就是一 ...

  5. C语言程序设计100例之(16):巧解算式

    例16  巧解算式 问题描述 在1.2.3.4.5.6.7.8.9.10个数中间加上加号或减号,使得到的表达式的值为自然数N,如果中间没有符号,则认为前后为一个数,如1 2 3认为是一百二十三(123 ...

  6. C语言程序设计100例之(15):除法算式

    例15   除法算式 问题描述 输入正整数n(2≤n≤68),按从小到大输出所有形如abcde/fghi=n的表达式.其中a~i为1~9的一个排列. 输入格式 每行为一个正整数n (n <= 1 ...

  7. C语言程序设计100例之(12):Eratosthenes筛法求质数

    例12   Eratosthenes筛法求质数 问题描述 Eratosthenes筛法的基本思想是:把某范围内的自然数从小到大依次排列好.宣布1不是质数,把它去掉:然后从余下的数中取出最小的数,宣布它 ...

  8. C语言程序设计100例之(4):水仙花数

    例4    水仙花数 题目描述 一个三位整数(100-999),若各位数的立方和等于该数自身,则称其为“水仙花数”(如:153=13+53+33),找出所有的这种数. 输入格式 没有输入 输出格式 若 ...

  9. C语言程序设计100例之(6):数字反转

    例6    数字反转 题目描述 给定一个整数,请将该数各个位上数字反转得到一个新数.新数也应满足整数的常见形式,即除非给定的原数为零,否则反转后得到的新数的最高位数字不应为零(参见样例2). 输入格式 ...

随机推荐

  1. 对主定理(Master Theorem)的理解

    前言 虽说在学OI的时候学到了非常多的有递归结构的算法或方法,也很清楚他们的复杂度,但更多时候只是能够大概脑补这些方法为什么是这个复杂度,而从未从定理的角度去严格证明他们.因此借着这个机会把主定理整个 ...

  2. CTF入门 |“男神”背后的隐写术

    刚刚开始学CTF,记录一下做的第一道隐写题 ~ 附件下载 题目背景(我自己瞎编的): Luyu是CPPU的校草,一直以来他的写真照被各届校友广泛流传,最近江湖上流传着拿到这些照片就能知道Luyu的QQ ...

  3. deepin开机自动启动服务备忘

    systemctl enable mysql.service(设置开机自启) sudo systemctl start nginx.service sudo systemctl restart ngi ...

  4. MPI Maelstrom POJ - 1502 floyd

    #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> usin ...

  5. Codeforces 474B. Worms

    It is lunch time for Mole. His friend, Marmot, prepared him a nice game for lunch. Marmot brought Mo ...

  6. 基于Web的网络商城项目设计与实现【SSM+Bootstrap+Vue】

    [Spring+SpringMVC+MyBatis+Bootstrap+Vue] 演示:线路1  线路2 1.系统功能介绍 网上商城系统 是一个功能完善的在线购物系统 - ,主要为在线销售和在线购物服 ...

  7. C#简单鼠标键盘钩子KMHook

    简介:由三个文件构成Pinvo.cs.KeyboardHook.cs.MouseHook.cs Pinvo.cs 是KeyboardHook与MouseHook需要的一些常量消息的定义 Keyboar ...

  8. Ubuntu下vsc+python3配置

    我发现直接搜这个很容易得到过时的文章py2请滚蛋好么 1.首先下去VSC官网下载.deb的安装包,安装好vsc,打开后安装PYTHON,reload下.别啊忘记修改路径,setting下搜python ...

  9. ubuntu apt 换源

    修改配置文件/etc/apt/sources.list 内容替换为 阿里镜像源 deb http://mirrors.aliyun.com/ubuntu/ vivid main restricted ...

  10. Go变量与常量

    变量与常量 变量声明 定义变量时指定变量类型式 定义变量时依靠类型推断 go是静态,强类型语言(java,c++也是如此). 静态语言: 在编译时就能确定变量类型的语言,类型推导在编译阶段可以不用指明 ...