【CCF-CSP201412-2】Z字形扫描

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

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 题目要求

在这里插入图片描述
在这里插入图片描述


2. 思考与解答

这道题目我想了比较久,找规律花的时间不多,但是如何模拟这个规律,调整输出的顺序,花了较多时间。思路如下:

  1. 每次扫描,一定是从左上角开始,到右下角为止。
  2. 数字个数非常有限,可以用二维数组模拟这一个图片矩阵;
  3. 有多个方向不同的扫描轨迹,如果把每个扫描轨迹划分为不同的组(互相平行的轨迹算做不同的扫描组),组号从 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 j0 开始按照规律一步一步调节,最后肯定是可以输出正确的结果的。不过这个规律看着非常简单,实际要直接通过指针模拟,我自己还是觉得特别复杂(尝试了好几次都不对)。

后来想到,数组一次一次调节 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-CSP 2024 年 12 月考试信息概述 #### 考试背景与目标 CCF-CSP(中国计算机学会软件能力认证)是一项旨在评估个人编程能力和算法设计水平的测试。该考试通常每年举办多次,每次都会提供一系列具有挑战性的题目供考生解答。对于即将举行的 CCF-CSP 2024 年 12 月考试,虽然具体细节尚未完全公开,但可以根据以往的趋势推测其形式和内容。 根据过往经验[^1],CSP 认证考试一般由四道编程题组成,难度依次递增。前三题主要考察基本的数据结构、控制流以及简单的算法实现;第四题则可能涉及较复杂的算法设计或优化技巧。因此,建议考生重点练习前三个问题的基础部,并逐步尝试解决第四个问题中的简化版本。 #### 解题策略与准备方法 针对即将到来的比赛,以下是几点备考建议: - **熟悉输入输出处理**:如同在相似度计算问题中所展示的一样,在程序开始阶段需正确获取所需数据量的信息,比如两个字符串列表各自的长度 `n` 和 `m` [^2]。 - **掌握核心知识点**: - 基础语法熟练运用; - 数据结构如数组、链表的操作; - 排序查找等经典算法的应用场景理解。 下面给出一段用于模拟读入多个整数值并存储到List集合内的Java代码片段作为示范: ```java import java.util.ArrayList; import java.util.Scanner; public class Main { public static void main(String[] args){ Scanner sc=new Scanner(System.in); int n=sc.nextInt(); // 获取第一个序列大小 ArrayList<Integer> listA=new ArrayList<>(); for(int i=0;i<n;i++)listA.add(sc.nextInt()); int m=sc.nextInt();// 获取第二个序列大小 ArrayList<Integer> listB=new ArrayList<>(); for(int j=0;j<m;j++)listB.add(sc.nextInt()); System.out.println("Data Loaded Successfully!"); } } ``` 通过上述实例可以看出如何有效地管理大规模数据集以便后续析比较操作得以顺利开展。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值