1. 题目要求


2. 思考与解答
这道题目我想了比较久,找规律花的时间不多,但是如何模拟这个规律,调整输出的顺序,花了较多时间。思路如下:
- 每次扫描,一定是从左上角开始,到右下角为止。
- 数字个数非常有限,可以用二维数组模拟这一个图片矩阵;
- 有多个方向不同的扫描轨迹,如果把每个扫描轨迹划分为不同的组(互相平行的轨迹算做不同的扫描组),组号从
0开始,那么就会有下面的扫描序列(给出依次扫描的每个元素的坐标序列从0开始,数组下标从0开始,以4x4矩阵为例):
第0组:(0, 0)
第1组:(0, 1) (1, 0)
第2组:(2, 0) (1, 1) (0, 2)
第3组:(0, 3) (1, 2) (2, 1) (3, 0)
... ...
第6组(3, 3)
输出的时候,就是从第 0 组开始从前往后依次输出对应坐标对应的数组元素的。
可以发现如下规律:
① 每一组中各个元素坐标之和等于组号
②奇数组,横坐标从 0 开始往上增长;偶数组,横坐标从对应的组号开始,往下递减;
修正,第二点规律对于后面几组数字的输出是不成立的,但是成立的规律是,奇数组元素的横坐标是顺序增长的,而偶数组的横坐标是倒序减少的,按照这个规律可以对奇数偶数组进行不同规则的排序。
找到了这个规律之后该如何模拟呢?
如果设置指针 i j 从 0 开始按照规律一步一步调节,最后肯定是可以输出正确的结果的。不过这个规律看着非常简单,实际要直接通过指针模拟,我自己还是觉得特别复杂(尝试了好几次都不对)。
后来想到,数组一次一次调节 i j 指针的办法,虽然一定是可以做出来的,但是很难模拟出以上规律(我把它称为分组规律)。要想模拟出分组规律,需要寻找其他的办法。
之后想到了用结构体排序 + vector 的办法。
思路如下:
第一步,循环输入数组元素时,存储好数组元素坐标 x y,用于组内排序
第二步,存储好数组元素的值 val,用于最后的输出
第三步,存储好数组坐标之和 z = x + y ,用于分组。
结构体设计如下:
struct Elem
{
int x;
int y;
int z;
int val;
bool operator<(Elem& e) const
{
if(z != e.z) return z < e.z;
else if(z % 2 == 0) return x > e.x;
else return x < e.x;
}
};
重载小于号用于排序:
一级规则:按照 z 也就是组号,升序排列;
二级规则:
判断 z,如果是偶数,就以横坐标降序排列(偶数组);如果是奇数,就按照横坐标升序排列(奇数组)。
排序最差 o(nlogn),这也是程序主体的复杂度。
完整代码如下,可以看到,这种办法非常完美地用程序解释了上面的思路,得到了正确的结果:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct Elem
{
int x;
int y;
int z;
int val;
bool operator<(Elem& e) const
{
if(z != e.z) return z < e.z;
else if(z % 2 == 0) return x > e.x;
else return x < e.x;
}
};
vector<Elem> v;
int main()
{
int n;
scanf("%d", &n);
int x;
for(int i = 0; i < n; i ++)
for(int j = 0; j < n; j ++)
{
scanf("%d", &x);
v.push_back({i, j, i + j, x});
}
sort(v.begin(), v.end());
int len = n * n;
for(int i = 0; i < len; i ++) printf("%d ", v[i].val);
return 0;
}
3. 总结
模拟还是要正确地用程序去表示某个流程或者体现某个规律,结构体和排序算法等在模拟题中往往特别重要。

本文介绍了CCF CSP201412的一道题目,涉及Z字形扫描问题。文章详细阐述了思考过程和解决方案,包括二维数组模拟、扫描规律的发现与应用,以及通过结构体排序的方法实现正确输出。总结强调模拟和排序算法在解决问题中的关键作用。

1498

被折叠的 条评论
为什么被折叠?



