7-5 螺旋方阵

news2024/7/4 6:00:43

 

分数 20

全屏浏览题目

切换布局

作者 C课程组

单位 浙江大学

所谓“螺旋方阵”,是指对任意给定的N,将1到N×N的数字从左上角第1个格子开始,按顺时针螺旋方向顺序填入N×N的方阵里。本题要求构造这样的螺旋方阵。

输入格式:

输入在一行中给出一个正整数N(<10)。

输出格式:

输出N×N的螺旋方阵。每行N个数字,每个数字占3位。

输入样例:

5

输出样例:

  1  2  3  4  5
 16 17 18 19  6
 15 24 25 20  7
 14 23 22 21  8
 13 12 11 10  9

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

我的答案:

分析过程:

  1. 螺旋方阵的填充模式为:先向右,然后向下,接着向左,最后向上,循环这四个方向。
  2. 向右和向左时,行数保持不变;向下和向上时,列数保持不变。
  3. 每完成一个方向的填充后,要缩小填充的范围。
  4. 填充完成的条件是已填入的数目等于 N×N。

解题过程:

  1. 初始化一个 N×N 的数组 matrix。
  2. 初始化当前方向为“向右”,当前行和列为 (0, 0)。
  3. 初始化一个计数器 counter 从1开始,每填充一个数字后加1。
  4. 根据当前方向进行填充,完成后改变方向。
  5. 根据方向,更新行或列的值。
  6. 当计数器大于 N×N 时,结束填充。
  7. 打印结果。

接下来,我们用 C 和 C++ 语言实现上述算法:

好的,我明白你的疑问。螺旋方阵的填充过程确实有点特殊。当我们沿着一个方向填充时,该方向上可填充的格子数量不是每次都一样的。具体来说,每完成一个循环(四个方向:右、下、左、上),其中的两个方向上可填充的格子数量都会减少一个。

详细分析如下:

1. **向右**:开始时,我们从最左边向右填充,可填充的格子数量是 N。
2. **向下**:当我们完成向右的填充后,开始向下填充,此时可填充的格子数量是 N-1,因为上边的第一行已经被填充。
3. **向左**:接着,我们向左填充,此时可填充的格子数量也是 N-1,因为下边的最后一行也已经被填充。
4. **向上**:最后,当我们向上填充时,可填充的格子数量是 N-2,因为除了第一行外,第二行也已经被填充。

接下来,当我们开始新的循环(第二次的右、下、左、上方向填充),可填充的格子数量会进一步减少。

这是因为在向右或向左填充时,由于上次循环中向下和向上的填充,已经使得上下两行被填充,所以此次循环中向右或向左时的填充格子数量会减少两个。相应地,在向下或向上填充时,由于上次循环中向右和向左的填充,已经使得左右两列被填充,所以此次循环中向下或向上时的填充格子数量会减少两个。

在代码中,我们通过检查每个格子是否已经被填充(即值为0)来决定是否继续当前方向的填充。这样,即使我们的循环设定了 N 次迭代,由于已填充的格子检查,我们可以自然地结束当前方向的填充并转向下一个方向。

C语言:

#include <stdio.h>

int main() {
    int N;
    scanf("%d", &N);
    int matrix[N][N];
    int row = 0, col = 0, num = 1, i;

    while (num <= N * N) {
        while (col < N && matrix[row][col] == 0) {
            matrix[row][col++] = num++;
        }
        col--; row++;
        while (row < N && matrix[row][col] == 0) {
            matrix[row++][col] = num++;
        }
        row--; col--;
        while (col >= 0 && matrix[row][col] == 0) {
            matrix[row][col--] = num++;
        }
        col++; row--;
        while (row >= 0 && matrix[row][col] == 0) {
            matrix[row--][col] = num++;
        }
        row++; col++;
    }

    for (i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            printf("%3d", matrix[i][j]);
        }
        printf("\n");
    }
    return 0;
}

C++:

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

int main() {
    int N;
    cin >> N;
    vector<vector<int>> matrix(N, vector<int>(N, 0));
    int row = 0, col = 0, num = 1;

    while (num <= N * N) {
        while (col < N && matrix[row][col] == 0) {
            matrix[row][col++] = num++;
        }
        col--; row++;
        while (row < N && matrix[row][col] == 0) {
            matrix[row++][col] = num++;
        }
        row--; col--;
        while (col >= 0 && matrix[row][col] == 0) {
            matrix[row][col--] = num++;
        }
        col++; row--;
        while (row >= 0 && matrix[row][col] == 0) {
            matrix[row--][col] = num++;
        }
        row++; col++;
    }

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            cout.width(3);
            cout << matrix[i][j];
        }
        cout << endl;
    }
    return 0;
}

注意:两种实现都采用了简单的嵌套循环,其中内层循环负责向某一方向填充,外层循环则负责切换方向。

C语言循环体详细解释:

首先,外部的 `while (num <= N * N)` 代表当我们填入的数字没有超过 `N*N` 时,我们就继续填充矩阵。

接下来是四个内部的 while 循环,分别代表向右、向下、向左、向上四个方向的填充。

1. **向右**:
    ```c
    while (col < N && matrix[row][col] == 0) {
        matrix[row][col++] = num++;
    }
    col--; row++;
    ```
    - `col < N` 保证列数没有超出范围。
    - `matrix[row][col] == 0` 检查当前格子是否为空(即值为0)。
    - `matrix[row][col++] = num++` 将数字填入当前格子,列数加1准备填充下一个格子,填入的数字加1。
    - 最后 `col--` 和 `row++` 是调整到下一个方向的起始点。

2. **向下**:
    ```c
    while (row < N && matrix[row][col] == 0) {
        matrix[row++][col] = num++;
    }
    row--; col--;
    ```
    - `row < N` 保证行数没有超出范围。
    - `matrix[row][col] == 0` 检查当前格子是否为空。
    - `matrix[row++][col] = num++` 将数字填入当前格子,行数加1准备填充下一个格子,填入的数字加1。
    - 最后 `row--` 和 `col--` 是调整到下一个方向的起始点。

3. **向左**:
    ```c
    while (col >= 0 && matrix[row][col] == 0) {
        matrix[row][col--] = num++;
    }
    col++; row--;
    ```
    - `col >= 0` 保证列数没有变为负数。
    - `matrix[row][col] == 0` 检查当前格子是否为空。
    - `matrix[row][col--] = num++` 将数字填入当前格子,列数减1准备填充下一个格子,填入的数字加1。
    - 最后 `col++` 和 `row--` 是调整到下一个方向的起始点。

4. **向上**:
    ```c
    while (row >= 0 && matrix[row][col] == 0) {
        matrix[row--][col] = num++;
    }
    row++; col++;
    ```
    - `row >= 0` 保证行数没有变为负数。
    - `matrix[row][col] == 0` 检查当前格子是否为空。
    - `matrix[row--][col] = num++` 将数字填入当前格子,行数减1准备填充下一个格子,填入的数字加1。
    - 最后 `row++` 和 `col++` 是调整到下一个循环开始的起始点。

这四个内部循环结束后,如果整个矩阵还没填满,那么整个外部循环会再次执行,继续从当前位置开始螺旋填充。

总结:

从这道关于螺旋方阵的题目中,我们可以学到很多有用的知识和技能:

1. **问题分析**:在开始编码之前,我们需要首先分析和理解题目。对于一些问题,如果没有明确的解题思路,直接编写代码可能会陷入混乱。通过深入地分析题目,我们可以识别出问题的核心要点,并形成一个清晰的解题策略。

2. **数组操作**:这题涉及到了二维数组的操作。对于新手来说,熟练掌握二维数组的初始化、访问和修改是非常基础的。

3. **循环控制**:题目中多层循环的使用,尤其是内部的四个方向的循环,帮助我们理解如何在循环中适时改变方向、跟踪状态并作出决策。

4. **边界条件处理**:处理数组时经常需要处理边界情况,例如确保索引没有超出数组的边界。这道题很好地体现了这一点。

5. **模拟问题解决**:这道题要求我们模拟螺旋填充的过程,这种模拟类的问题在实际编程和算法竞赛中都非常常见。通过解决此类问题,我们可以加强对复杂过程模拟的能力。

6. **代码整洁和结构**:良好的代码应当具备清晰的结构和易读性。这道题给了我们一个机会,让我们思考如何组织代码,使其不仅能够工作,而且具有良好的可读性和可维护性。

7. **调试与测试**:完成代码编写后,我们需要进行测试。设计一些测试用例,特别是一些边界情况,可以帮助我们发现并修复代码中的错误。

总的来说,这道题目为我们提供了一个综合练习的机会,让我们运用和巩固在数据结构、算法和编程中学到的知识和技能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/905195.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第3步---MySQL的DDL和DML操作

第3步---MySQL的DDL和DML操作 1.DDL操作 Data Defination Language 数据定义语言。创建数据库和表的不涉及到数据的操作。 1.1DDL基本操作 1.1.1数据库相关操作 ddl&#xff1a;创建数据库&#xff0c;创建和修改表 对数据库常见的操作&#xff1a; 操作数据库 -- 展示数据…

Unity 之 Input类

文章目录 总述具体介绍 总述 Input 类是 Unity 中用于处理用户输入的重要工具&#xff0c;它允许您获取来自键盘、鼠标、触摸屏和控制器等设备的输入数据。通过 Input 类&#xff0c;您可以轻松地检测按键、鼠标点击、鼠标移动、触摸、控制器按钮等用户输入事件。以下是关于 I…

拥塞控制(TCP限制窗口大小的机制)

拥塞控制机制可以使滑动窗口在保证可靠性的前提下&#xff0c;提高传输效率 关于滑动窗口的属性以及部分机制推荐看TCP中窗口和滑动窗口的含义以及流量控制 拥塞控制出现的原因 看了上面推荐的博客我们已经知道了&#xff0c;由于接收方接收数据的能力有限&#xff0c;所以要通…

js IntersectionObserver简单案例

效果 源码 <!DOCTYPE html> <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content&q…

IP库新增经过实践的Verilog 库

网上严重缺乏实用的 Verilog 设计。Project F 库是尝试让 FPGA 初学者变得更好部分。 设计包括 Clock- 时钟生成 (PLL) 和域交叉Display - 显示时序、帧缓冲区、DVI/HDMI 输出Essential- 适用于多种设计的便捷模块Graphics- 绘制线条和形状Maths- 除法、LFSR、平方根、正弦....…

Vue--》打造个性化医疗服务的医院预约系统(七)完结篇

今天开始使用 vue3 + ts 搭建一个医院预约系统的前台页面,因为文章会将项目的每一个地方代码的书写都会讲解到,所以本项目会分成好几篇文章进行讲解,我会在最后一篇文章中会将项目代码开源到我的GithHub上,大家可以自行去进行下载运行,希望本文章对有帮助的朋友们能多多关…

Android OpenCV(七十四): Android OpenCV SDK 升级至 4.8.0

前言 如昨日文章所述,OpenCV 4.8.0 已经发布,虽然系列文章已经停更很久,但是版本升级工作笔者是很乐意快速完成的。 OpenCV 4.8.0 Android SDK:https://github.com/opencv/opencv/releases/download/4.8.0/opencv-4.8.0-android-sdk.zip 更新日志:https://github.com/o…

Apache Doris IP变更问题详解

Apache Doris IP变更问题详解 一、背景二、环境硬件信息软件信息 三、FE恢复3.1 异常日志3.2 获取当前ip3.3 重置ip信息3.4 重置元数据记录3.5 元数据模式恢复3.6 重置fe集群节点3.7 关闭元数据模式重启fe 四、BE恢复4.1 获取当前ip4.2 重置ip信息4.3 重置be集群节点 一、背景 …

简单、快速、无需注册的在线 MockJs 工具

简单、快速、无需注册的 MockJs 工具。通过参数来返回数据&#xff0c;传入什么参数就返回什么数据。 使用 接口只支持返回文本类数据&#xff0c;不支持图片、流数据等。 json 调用接口 https://mock.starxg.com/?responseBody{“say”:“hello”}&contentTypeapplic…

13.减少磁盘延迟方法

第四章 文件管理 13.减少磁盘延迟时间的方法 ​   (盘面号&#xff0c;柱面号&#xff0c;扇区号)&#xff0c;且需要连续读取物理地址(00&#xff0c;000&#xff0c;000)&#xff5e;(00&#xff0c;001&#xff0c;111)的扇区。先读取(00&#xff0c;000&#xff0c;000)…

qiuzhiji3

本篇想介绍一下慧与&#xff0c;这里的工作氛围和企业文化令人难忘&#xff0c;希望更多人了解它 也想探讨一下不同的文化铸就的不同企业&#xff0c;究竟有哪些差别。 本篇将从我个人角度出发描述慧与。 2022/3/16至2023/7/31 本篇初次写于2023年8月20日 说起来在毕业之前那段…

jstat(JVM Statistics Monitoring Tool):虚拟机统计信息监视工具

jstat&#xff08;JVM Statistics Monitoring Tool&#xff09;&#xff1a;虚拟机统计信息监视工具 用于监视虚拟机各种运行状态信息的命令行工具。 它可以显示本地或者远程虚拟机进程中的类加载、内存、垃圾收集、即时编译等运行时数据&#xff0c;在没有GUI图形界面、只提…

多地图-RRT算法规划路径

RRT算法 %% %% 初始化 mapim2bw(imread(map2.bmp)); % bmp无损压缩图像500x500,im2bw把灰度图转换成二值图像01 source[10 10]; % 起始点位置 goal[490 490]; % 目标点位置 stepsize20; % RRT每步步长 disTh20; % 直到qnearest和目标点qgaol距离小于一个阈值 maxFailedAttemp…

Nacos配置管理、Feign远程调用、Gateway服务网关

1.Nacos配置管理 1.1.将配置交给Nacos管理的步骤 1.在Nacos中添加配置 Data Id服务名称-环境名称.yaml eg&#xff1a;userservice-dev.yaml 2.引入nacos-config依赖 在user-service服务中&#xff0c;引入nacos-config的客户端依赖 <!--nacos配置管理依赖--> <dep…

verilog defparam

verilog defparam 文章目录 verilog defparam一、背景二、模块例化传参与defparam的对比2.1 带参数模块例化的例子2.2 defparam的例子 三、defparam3.1 例子 一、背景 当一个模块被另一个模块引用例化时&#xff0c;高层模块可以对低层模块的参数值进行改写。这样就允许在编译…

Verilog中的 条件语句\多路分支语句\循环语句

Verilog中的条件语句\多分支语句\循环语句 文章目录 Verilog中的条件语句\多分支语句\循环语句一、背景二、if-else2.1 标准结构2.2 例子 三、case-endcase3.1 标准结构3.2 例子3.2.1 三路选择器的case部分&#xff0c;如下&#xff1a;3.2.2 casez的四路选择器&#xff0c;如下…

5.6.webrtc三大线程

那今天呢&#xff1f;我们来介绍一下web rtc的三大线程&#xff0c;那为什么要介绍这三大线程呢&#xff1f;最关键的原因在于web rtc的所有其他线程都是由这三大线程所创建的。那当我们将这三个线程理解清楚之后呢&#xff1f;我们就知道其他线程与它们之间是怎样关系&#xf…

14.磁盘的管理

第四章 文件管理 14.磁盘的管理 自举程序比较复杂&#xff0c;所以无法保证自举程序相关的数据永远不改变&#xff0c;这个问题该如何解决&#xff1f; 自举装入程序的复杂度不高&#xff0c;很小&#xff0c;所以可以保证自举装入程序是不会出错的&#xff0c;不需要更改的&…

C语言小白急救 整型与浮点型在内存中的存储

文章目录 一、有无符号整型的存储1.整形家族2.整形在内存中的存储3.大小端介绍4.unsigned 类型存储 二、浮点型的存储1.浮点型家族2.浮点型的存储 一、有无符号整型的存储 1.整形家族 字符在内存中存储的是字符的ASCII码值&#xff0c;ASCII码值是整形&#xff0c;所以它也归于…

【C++】做一个飞机空战小游戏(十一)——游戏过关、通关、结束的设置

[导读]本系列博文内容链接如下&#xff1a; 【C】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值 【C】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动【C】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动 【C】做一个飞…