P4924 [1007]魔法少女小Scarlet 题解

题目传递门

解题思路:

看到数据范围后知道这道题是道模拟,然后我们又发现数据的范围保证不会出现越界的情况(良心啊qwq),所以我们不需要特别判断是否越界。然而我比较菜,推了大半天式子还错了。。 因为矩阵是绕着某个中心\((x,y)\)旋转的而且保证是正方形,为了得到正确的式子、便于理解,我们不妨设\((x,y)\)为原点\((0,0)\),这样稍微模拟一下就可以得到顺时针旋转90°后正方形上一点\((i,j)\)坐标变成\((j,-i)\),逆时针旋转90°后坐标变成\((-j,i)\),然后枚举\(i,j\)即可。

注意:
这里可能有的同学不理解,我们明明在是数组上操作,数组上操作是没有负号的,你上面怎么用直角坐标系来推导?那个负号怎么办啊?

其实,在数组中,我们并不是从\((0,0)\)这个点为中心的,而是以\((x,y)\)为中心,就是每个推导的结果在横坐标和纵坐标上要分别加上\(x,y\)就是可解决到负号的问题,这个也就是坐标平移的意思了。

再深层的含义,可能需要纸和笔按样例使用推出来的公式验证一下就明白了。> 很简单的(开玩笑,很简单???)

下面的准备的知识点,先试一下吧:

1、二维数组顺时针旋转90度

#include <bits/stdc++.h>

using namespace std;

// Rotate Image(二维数组顺时针旋转90度)
const int N = 110;
int n = 9, cnt;

int res[N][N], tmp[N][N];

//矩阵旋转,需要额外开创建一个临时的二维数组(防止出现交换赋值时,出现覆盖的问题)
void rotate(int x, int y, int r) {
    for (int i = -r; i <= r; i++)
        for (int j = -r; j <= r; j++)
            //每一个位置都去了哪里
            tmp[x + j][y - i] = res[x + i][y + j];
    //复制回来
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            res[i][j] = tmp[i][j];
}

int main() {
    //初始化数据
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            res[i][j] = tmp[i][j] = ++cnt;

    //输出结果
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++)
            printf("%2d ", res[i][j]);
        printf("\n");
    }

    printf("\n");

    //测试一下旋转
    rotate(6, 7, 1);

    //输出结果
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++)
            printf("%2d ", res[i][j]);
        printf("\n");
    }
    return 0;
}

2、二维数组逆时针旋转90度

#include <bits/stdc++.h>

using namespace std;

// Rotate Image(二维数组逆时针旋转90度)
const int N = 110;
int n = 9, cnt;
int res[N][N], tmp[N][N];

//矩阵旋转,需要额外开创建一个临时的二维数组(防止出现交换赋值时,出现覆盖的问题)
void rotate(int x, int y, int r) {
    for (int i = -r; i <= r; i++)
        for (int j = -r; j <= r; j++)
            tmp[x - j][y + i] = res[x + i][y + j];

    //复制回来
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            res[i][j] = tmp[i][j];
}

int main() {
    //初始化数据
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            res[i][j] = tmp[i][j] = ++cnt;

    //输出结果
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++)
            printf("%02d ", res[i][j]);
        printf("\n");
    }

    printf("\n");

    //测试一下旋转
    rotate(6, 7, 1);

    //输出结果
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++)
            printf("%02d ", res[i][j]);
        printf("\n");
    }
    return 0;
}

3、本题解答

#include<bits/stdc++.h>

using namespace std;
const int N = 510;
int n, m;
int x, y, r, z;
int tmp[N][N], res[N][N];
int cnt;

// 数组res为最后输出的结果数组,tmp为辅助数组;
int main() {
    cin >> n >> m;
    //初始化数据
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            res[i][j] = tmp[i][j] = ++cnt;

    //读入魔法指令
    while (m--) {//m次指令
        cin >> x >> y >> r >> z;

        //处理旋转
        if (z == 0) { //顺时针
            for (int i = -r; i <= r; i++) //i为以(x,y)为中点的偏移量,可以用来描述横坐标
                for (int j = -r; j <= r; j++)//j为以(x,y)为中点的偏移量,可以用来描述纵坐标
                    //防止自己覆盖掉自己,在副本上操作
                    //遍历每一个范围内的坐标,根据上图,确定最终的坐标
                    res[x + j][y - i] = tmp[x + i][y + j];
        } else if (z == 1) {//逆时针
            for (int i = -r; i <= r; i++)
                for (int j = -r; j <= r; j++)
                    //防止自己覆盖掉自己,在副本上操作
                    //遍历每一个范围内的坐标,根据上图,确定最终的坐标
                    res[x - j][y + i] = tmp[x + i][y + j];
        }
        //更新辅助数组
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                tmp[i][j] = res[i][j];
    }
    //输出
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) cout << res[i][j] << ' ';
        cout << endl;
    }
    return 0;
}
posted @ 2021-07-07 14:05  糖豆爸爸  阅读(437)  评论(0编辑  收藏  举报
Live2D