P5731 【深基5.习6】蛇形方阵

二维数组 / 螺旋模拟 / 边界收缩

一、先回答问题

这题到底在考什么

把填数过程看成一圈一圈向内收缩:顶行向右、右列向下、底行向左、左列向上。

对象

保留四条边界 top、bottom、left、right,以及下一个要填的 num;每填完一条边就把对应边界向内缩。

为什么能这样做

每个格子只被填一次,边界收缩能避免反复判断是否撞墙。

先避开的坑

最容易在奇数 n 的中心格多填或漏填,所以每走完一段要确认 num 还没超过 n*n。

二、互动演示

n=4 的四边界收缩

演示进度

课堂要求:每一步都让学生说出当前保留了什么信息,以及下一步为什么不会漏答案。

三、手推结果

把关键过程写成表

阶段边界变化填入位置
顶行top++(1,1) 到 (1,4)
右列right--(2,4) 到 (4,4)
底行bottom--(4,3) 到 (4,1)
左列left++(3,1) 到 (2,1)
四、自己选答案

当堂检查

为什么输出要用 setw(3)?
四边界法中 top++ 表示什么?
五、C++14 参考代码

代码读慢一点

#include <bits/stdc++.h>
using namespace std;

int a[15][15];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;

    int num = 1, target = n * n;
    int top = 1, bottom = n, left = 1, right = n;

    while (num <= target) {
        for (int i = left; i <= right; ++i) a[top][i] = num++;
        top++;

        for (int i = top; i <= bottom; ++i) a[i][right] = num++;
        right--;

        if (num <= target) {
            for (int i = right; i >= left; --i) a[bottom][i] = num++;
            bottom--;
        }

        if (num <= target) {
            for (int i = bottom; i >= top; --i) a[i][left] = num++;
            left++;
        }
    }

    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            cout << setw(3) << a[i][j];
        }
        cout << "\n";
    }

    return 0;
}

读代码抓这几处

六、收口

复杂度与常见错误

复杂度:时间 O(n^2),空间 O(n^2)。

源文件:Problems/P5731.md · Problems/P5731_solution.md