D. 旋转棋盘
题目描述
输入样例
5 5 3
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
1 1 2
1 2 2
2 1 3
输出样例
0 1 0 3 4
0 0 1 3 4
1 1 2 3 4
2 2 2 3 4
0 1 2 3 4
数据范围
对于30%的数据,1<N, M ,Q ≤ 100;
对于另外30%的数据,保证
两之间不相交或相等;
对于100%的数据,1≤N , M,Q ≤2000。所有数取值都为0~9。
解题思路
- 模拟解法:顺时针旋转90deg 等价于先进性转置,再进中心对称的列转化。这样可以过30% 的数据。
- 第二种也是模拟解法, 把对应的三角区域的数据沿着顺时针方向旋转 。 这样速度可以加快50%。 因为遍历的数据少了只有四分之一矩阵。
#include <algorithm>
#include <cstring>
#include <iostream>
#include <stdio.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
int a[2002][2002];
inline int read()
{
int x = 0, f = 1;
char s = getchar();
while (s < '0' || s > '9')
{
if (s == '-')
f = -f;
s = getchar();
}
while (s >= '0' && s <= '9')
{
x = (x << 3) + (x << 1) + (s ^ 48);
s = getchar();
}
return x * f;
}
void rotate(int x, int y, int c)// 旋转矩阵第一种写法。
{
// 矩阵转置(行和列互换)
for (int i = 0; i <= c - 1; i++)
{
for (int j = 0; j <= i; j++)
swap(a[i + x][j + y], a[j + x][i + y]);
}
//矩阵中心对称交换,即第一列和最后一列交换
for (int i = 0; i <= c - 1; i++)
for (int j = 0; j <= (c >> 1) - 1; j++)
{
int temp = a[i + x][j + y];
a[i + x][j + y] = a[i + x][c - 1 + y - j];
a[i + x][c - 1 + y - j] = temp;
}
}
void work(int x, int y, int c) // 旋转矩阵第二种写法。
{
int N = c - 1;
for (int i = 0; i < c / 2; i++)
for (int j = i; j < N - i; j++)
{
int temp = a[i + x][j + y];
a[i + x][j + y] = a[N - j + x][i + y];
a[N - j + x][i + y] = a[N - i + x][N - j + y];
a[N - i + x][N - j + y] = a[j + x][N - i + y];
a[j + x][N - i + y] = temp;
}
}
int main()
{
freopen("rotate.in", "r", stdin); //输入重定向,目录下的in.txt文件中读取
freopen("rotate.out", "w", stdout); //输出重定向,目录下的out.txt文件中
输入
int n = read(), m = read(), q = read();
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
a[i][j] = read();
操作
while (q--)
{
int x = read(), y = read(), c = read();
rotate(x, y, c);
}
输出
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
printf("%d ", a[i][j]);
printf("\n");
}
return 0;
}
终极解法:
使用链表。
由于旋转之后,虽然方块内数的上下左右变化了,但是他们的相对位置不变,仅有正方形的边上的数改变了原来连接的数,那么我们只要改变这些数即可。
在链表上访问时,我们可以通过两个数确定一条直线,即不断从一个数向另一个数的方向走,这样就能访问到确定位置的数。
Coding…!
#include <algorithm>
#include <cstring>
#include <iostream>
#include <stdio.h>
using namespace std;
const int N = 2005, M = 5e6 + 5;
int p[M][4], ans[N][N], g[N][N];
int n, m, Q, val[M], a[8], b[8];
inline void Search(int id, int stp, int &A, int &B)
{
int now = p[id][0], pre = id;
for (int i = 1; i <= stp; ++i)
{
for (int j = 0; j < 4; ++j)
if (p[now][j] == pre)
{
pre = now;
now = p[now][j ^ 1];
break;
}
}
A = pre;
B = now;
}
inline int read()
{
int x = 0, f = 1;
char s = getchar();
while (s < '0' || s > '9')
{
if (s == '-')
f = -f;
s = getchar();
}
while (s >= '0' && s <= '9')
{
x = (x << 3) + (x << 1) + (s ^ 48);
s = getchar();
}
return x * f;
}
int main()
{
// freopen("rotate.in", "r", stdin); //输入重定向,
// freopen("rotate.out", "w", stdout); //输出重定向,
n = read(), m = read(), Q = read();
// 给位置编号,
for (int i = 0, im = n + 1; i <= im; ++i)
for (int j = 0, jm = m + 1; j <= jm; ++j)
g[i][j] = i * (m + 2) + j;
// 初始化链表
for (int i = 1; i <= m; ++i)
{
p[g[0][i]][0] = g[1][i];
p[g[0][i]][2] = g[0][i - 1];
p[g[0][i]][3] = g[0][i + 1];
p[g[n + 1][i]][0] = g[n][i];
p[g[n + 1][i]][2] = g[n + 1][i - 1];
p[g[n + 1][i]][3] = g[n + 1][i + 1];
}
for (int i = 1; i <= n; ++i)
{
p[g[i][0]][0] = g[i][1];
p[g[i][0]][2] = g[i - 1][0];
p[g[i][0]][3] = g[i + 1][0];
p[g[i][m + 1]][0] = g[i][m];
p[g[i][m + 1]][2] = g[i - 1][m + 1];
p[g[i][m + 1]][3] = g[i + 1][m + 1];
}
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
{
val[g[i][j]] = read();
p[g[i][j]][2] = g[i - 1][j];
p[g[i][j]][3] = g[i + 1][j];
p[g[i][j]][0] = g[i][j - 1];
p[g[i][j]][1] = g[i][j + 1];
}
// 处理数据
int x, y, c;
while (Q--)
{
x = read(), y = read(), c = read();
if (c == 1)
continue;
// 对边界进行处理
Search(g[x][0], y - 1, a[0], b[0]);
Search(g[x + 1][0], y - 1, a[4], b[4]);
Search(g[0][y + c - 1], x - 1, a[1], b[1]);
Search(g[0][y + c - 2], x - 1, a[5], b[5]);
Search(g[x + c - 1][m + 1], m - y - c + 1, a[2], b[2]);
Search(g[x + c - 2][m + 1], m - y - c + 1, a[6], b[6]);
Search(g[n + 1][y], n - x - c + 1, a[3], b[3]);
Search(g[n + 1][y + 1], n - x - c + 1, a[7], b[7]);
for (int i = 1; i <= c; ++i)
{
for (int j = 0; j < 4; ++j)
{
for (int k = 0; k < 4; ++k)
if (p[a[j]][k] == b[j])
{
p[a[j]][k] = b[!j ? 3 : j - 1];
break;
}
for (int k = 0; k < 4; ++k)
if (p[b[j]][k] == a[j])
{
p[b[j]][k] = a[j == 3 ? 0 : j + 1];
break;
}
}
for (int j = 0; j < 4; ++j)
{
for (int k = 0; k < 4; ++k)
if (p[a[j + 4]][k] == a[j])
{
a[j] = a[j + 4];
a[j + 4] = p[a[j + 4]][k ^ 1];
break;
}
for (int k = 0; k < 4; ++k)
if (p[b[j + 4]][k] == b[j])
{
b[j] = b[j + 4];
b[j + 4] = p[b[j + 4]][k ^ 1];
break;
}
}
}
}
// 处理最后数组
for (int i = 1; i <= n; ++i)
{
int pre = g[i][0], now = p[pre][0];
for (int j = 1; j <= m; ++j)
{
ans[i][j] = val[now];
for (int k = 0; k < 4; ++k)
if (p[now][k] == pre)
{
pre = now;
now = p[now][k ^ 1];
break;
}
}
}
// 输出数据
for (int i = 1; i <= n; ++i, putchar('\n'))
for (int j = 1; j <= m; ++j)
putchar(ans[i][j] + '0'), putchar(' ');
//fclose(stdin);
//fclose(stdout);
return 0;
}