例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. Google Waymo自动驾驶安全技术报告(二)

    Waymo的技术在公开道路上.封闭测试场.仿真器进行了广泛的测试,所以可以保证自动驾驶系统的每一部分在其ODD内都有强大.可靠.安全的处理能力. Waymo的自动驾驶系统由三个相互独立.严格测试的子系 ...

  2. Dart单例模式最佳实践

    /// Created by Capt. Michael @ CaptNotes.com on 02/17/2020. class Singleton { Singleton._(); static ...

  3. jQuery---html方法和text方法

    html方法和text方法 //html:innerHTML text:innerText console.log($("div").html());//<h3>我是标 ...

  4. 【巨杉数据库SequoiaDB】巨杉Tech | 四步走,快速诊断数据库集群状态

    1.背景 SequoiaDB 巨杉数据库是一款金融级分布式数据库,包括了分布式 NewSQL.分布式文件系统与对象存储.与高性能 NoSQL 三种存储模式,分别对应分布式在线交易.非结构化数据和内容管 ...

  5. Win10安装5 —— 系统安装步骤

    本文内容皆为作者原创,如需转载,请注明出处:https://www.cnblogs.com/xuexianqi/p/12369698.html 1.打开U盘中的解压好的文件夹后,双击打开"s ...

  6. Hdu2097 Sky数

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2097 Problem Description Sky从小喜欢奇特的东西,而且天生对数字特别敏感,一次偶 ...

  7. [TJOI2009] 猜数字 - 中国剩余定理

    现有两组数字,每组k个,第一组中的数字分别为:a1,a2,...,ak表示,第二组中的数字分别用b1,b2,...,bk表示.其中第二组中的数字是两两互素的.求最小的非负整数n,满足对于任意的i,n ...

  8. ActiveMQ的p2p模式与发布订阅模式

    1.消息中间件:采用异步通讯防止,支持点对点以及发布订阅模式,可以解决高并发问题        传统调用接口,可能发生阻塞,重复提交,超时等等问题,可以利用消息中间件发送异步通讯请求          ...

  9. leetcode腾讯精选练习之相交链表(六)

    相交链表 题目: 编写一个程序,找到两个单链表相交的起始节点. 如下面的两个链表: 在节点 c1 开始相交. 示例 1: 输入:intersectVal = 8, listA = [4,1,8,4,5 ...

  10. Appium连接模拟器

    Appnium 环境搭建 覆盖文件 将SDK中platform-tools目录下的这三个文件 复制到模拟安装路径bin目录下,覆盖原有的这三个文件 adb命令 开启服务 adb start-serve ...