传送门:Character Wheels

题意

给你一个n*n的矩阵,保证n为偶数。从外向内总共n/2层,现在有m次操作,对于每次操作:
1. 选择其中一层向左(逆时针)或向右(顺时针)转动y次。
2. 输出当前的矩阵。

思路

直接模拟。
- 如果要输出矩阵。对于每层,按矩阵的左上->右上->右下->左下的顺序维护一个线性表。若需输出新矩阵则遍历该线性表,按其对应位置存入答案矩阵即可。
- 如果要选择一层转动y次。设num=y%4,若num!=0,则向右转动num次,等效于向左转动4-num次。然后更新每一层在对应线性表中的开始位置。

AC代码

#include <bits/stdc++.h>
using namespace std;
const int N=52;
int n,m;
char a[N][N],ans[N][N];
int dir[4][2]={0,1,1,0,0,-1,-1,0}; // 右、下、左、上
vector<char>g[N]; // 按矩阵的左上->右上->右下->左下的顺序维护一个线性表
int pos[N]; // 记录第i层的首个字符在g[i]中的下标
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            cin>>a[i][j];
    int h=n/2; // h层
    for(int i=1;i<=h;i++)
    {
        pos[i]=0;
        int bx=i;
        int by=i;
        int k=0; // 方向
        int x=bx,y=by;
        while(1)
        {
            if(k==3&&x==bx&&y==by)break; // 向上回到起点,结束
            g[i].push_back(a[x][y]);
            int d=(h-i+1)*2-1;
            if(k==0&&x==bx&&y==by+d) // 右上角,改变方向
                k++;
            else if(k==1&&x==bx+d&&y==by+d) // 右下角
                k++;
            else if(k==2&&x==bx+d&&y==by) // 左下角
                k++;
            x+=dir[k][0];
            y+=dir[k][1];
        }
    }
    cin>>m;
    char opt;
    while(m--)
    {
        cin>>opt;
        int k,num;
        if(opt=='P')
        {
            for(int i=1;i<=h;i++)
            {
                int bx=i,by=i;
                int x=bx,y=by;
                int cnt=pos[i];
                int k=0; // 方向
                while(1)
                {
                    if(k==3&&x==bx&&y==by)break; // 向上回到起点,结束
                    ans[x][y]=g[i][cnt];
                    cnt=(cnt+1)%g[i].size(); // 记得取模
                    int d=(h-i+1)*2-1;
                    if(k==0&&x==bx&&y==by+d) // 右上角,改变方向
                        k++;
                    else if(k==1&&x==bx+d&&y==by+d) // 右下角
                        k++;
                    else if(k==2&&x==bx+d&&y==by) // 左下角
                        k++;
                    x+=dir[k][0];
                    y+=dir[k][1];
                }
            }
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    j==n?printf("%c\n",ans[i][j]):printf("%c",ans[i][j]);
        }
        else
        {
            cin>>k>>num;
            num%=4;
            if(opt=='R'&&num!=0)num=4-num; // 转换成L
            int d=(h-k+1)*2-1;
            pos[k]=(pos[k]+num*d)%g[k].size();
        }
    }
    return 0;
}

UPDATE 2020.11.1 简化

其实不用按顺序放到线性表里,可直接修改原矩阵,每次交换4个位置,来调整顺序。

#include <bits/stdc++.h>
using namespace std;
const int N=52;
int n,m;
char s[N][N];
void rot(int k,int num) // 第k层左转num次
{
    int h=n/2; // 共h层
    int d=(h+1-k)*2; // 第k层行(列)的长度
    while(num--)
    {
        for(int i=1;i<=d-1;i++)
        {
            int x1=k,y1=k+i-1; // 左上角往右第i个 (x1,y1)
            int x2=k+i-1,y2=k+d-1; // 右上角往下第i个 (x2,y2)
            int x3=k+d-1,y3=k+d-i; // 右下角往左第i个 (x3,y3)
            int x4=k+d-i,y4=k; // 左下角往上第i个 (x4,y4)
            swap(s[x1][y1],s[x2][y2]);
            swap(s[x2][y2],s[x3][y3]);
            swap(s[x3][y3],s[x4][y4]);
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>s[i]+1;
    cin>>m;
    while(m--)
    {
        char opt;
        cin>>opt;
        if(opt=='P')
        {
            for(int i=1;i<=n;i++)
                printf("%s\n",s[i]+1);
        }
        else
        {
            int k,num;
            cin>>k>>num;
            num%=4;
            if(opt=='R'&&num!=0)num=4-num; // 转换成L
            rot(k,num);
        }
    }
    return 0;
}