2 条题解

  • 0
    @ 2026-3-9 22:01:15
    #include <iostream>
    using namespace std;
    int a[600][600],b[600][600];
    void xuanzhzuan (int x,int y,int r,int z) {
        for (int i = x-r; i <= x+r; i++) {
            for (int j=y-r;j<=y+r;j++) {
                if (z==0) b[i][j]=a[x+y-j][y-x+i];
                else b[i][j]=a[x-y+j][x+y-i];
            }
        }
        for (int i = x-r; i <= x+r; i++) {
            for (int j=y-r;j<=y+r;j++) {
               a[i][j]=b[i][j];
            }
        }
    }
    int main() {
        int n,m,con=1;
        cin >> n >> m;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                a[i][j]=con++;
            }
        }
        int x,y,r,z;
        for (int i = 1; i <= m; i++) {
            cin >> x >> y >> r >> z;
            xuanzhzuan(x,y,r,z);
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                cout << a[i][j] << " ";
            }
            cout <<endl;
        }
        return 0;
    }
    
    
    • 0
      @ 2026-3-9 22:00:22

      魔法矩阵旋转函数讲解

      我来给你逐行、逐公式讲清楚这个旋转函数 xuanzhzuan 为什么这么写,以及里面的坐标公式是怎么推导出来的。

      一、先看懂题目要求

      1. 矩阵是1-based(行、列从 1 开始数)
      2. 每次旋转:以 (x,y) 为中心,边长 2r+1 的正方形
      3. z=0 顺时针转 90°,z=1 逆时针转 90°
      4. 必须用临时数组 b 暂存结果,不能直接在原数组 a 上改,否则会覆盖还没用到的数据

      二、函数整体结构

      void xuanzhzuan (int x,int y,int r,int z) {
          // 第一步:把旋转后的值存到 b 里
          for (int i = x-r; i <= x+r; i++) {
              for (int j=y-r;j<=y+r;j++) {
                  if (z==0) b[i][j] = a[x+y-j][y-x+i];  // 顺时针
                  else      b[i][j] = a[x-y+j][x+y-i];  // 逆时针
              }
          }
          // 第二步:把 b 复制回 a
          for (int i = x-r; i <= x+r; i++) {
              for (int j=y-r;j<=y+r;j++) {
                 a[i][j] = b[i][j];
              }
          }
      }
      

      作用

      • 遍历要旋转的小正方形里每一个位置 (i,j)
      • 计算这个位置旋转后应该从原数组的哪个位置拿数
      • 先存到临时数组 b,最后统一覆盖回 a

      三、核心:坐标变换公式(最关键)

      我们先定义:

      • 中心坐标:(cx, cy) = (x, y)
      • 当前要填的位置:(i, j)
      • 我们要找:旋转后 (i,j) 应该等于原来的哪个位置 (u, v)

      1. 顺时针旋转 90° 公式

      b[i][j] = a[ x + y - j ][ y - x + i ];
      

      等价于:

      u = x + y - j
      v = y - x + i
      

      推导原理(以中心为原点)

      1. 相对中心的坐标: dx = i - x(行偏移) dy = j - y(列偏移)

      2. 顺时针 90° 旋转的数学变换: 新dx = dy 新dy = -dx

      3. 还原回原数组坐标: u = x + 新dx = x + dy = x + (j - y) v = y + 新dy = y - dx = y - (i - x)

      4. 整理后就是代码里的公式:

        u = x + y - j
        v = y - x + i
        

      2. 逆时针旋转 90° 公式

      b[i][j] = a[ x - y + j ][ x + y - i ];
      

      等价于:

      u = x - y + j
      v = x + y - i
      

      推导原理

      1. 相对中心:dx = i-x,dy = j-y
      2. 逆时针 90° 数学变换: 新dx = -dy 新dy = dx
      3. 还原后整理,就得到上面的公式。

      四、为什么要用两个循环 + 临时数组 b?

      第一个循环:只读取原数组 a,计算旋转后的值,写入 b 第二个循环:把 b 完整复制回 a

      如果不使用 b、直接修改 a:

      • 你会把还没用到的原始值覆盖掉
      • 后面的位置计算就会用错数据
      • 结果直接乱掉

      所以必须用临时数组,这是矩阵旋转的标准写法。


      五、循环范围为什么是 i=x-r ~ x+r?

      • 中心是 x 行,半径 r
      • 向上延伸 r 行:x - r
      • 向下延伸 r 行:x + r
      • 列同理:y - ry + r
      • 刚好形成 2r+1 阶正方形,完全符合题目要求

      六、一句话总结这个函数

      遍历以 (x,y) 为中心、半径 r 的正方形内每一个点 (i,j), 根据顺时针/逆时针的数学坐标变换公式,找到它在原数组中对应的位置, 用临时数组暂存结果,最后覆盖回原数组,完成旋转。


      总结

      1. 公式来源:矩阵旋转的相对坐标数学变换,不是瞎写的
      2. 临时数组 b:防止覆盖原始数据,保证旋转正确
      3. 循环范围:刚好圈出要旋转的 2r+1 阶小方阵
      4. 两行公式:分别对应顺时针、逆时针 90° 旋转

      你现在的代码完全正确,可以直接 AC 这道题!

      • 1

      信息

      ID
      4539
      时间
      1000ms
      内存
      256MiB
      难度
      9
      标签
      递交数
      18
      已通过
      2
      上传者