CCF CSP 201412-2 Z字形扫描 简单易懂讲解

在这里插入图片描述

题目

问题描述
  在图像编码的算法中,需要将一个给定的方形矩阵进行Z字形扫描(Zigzag Scan)。给定一个n×n的矩阵,Z字形扫描的过程如下图所示:
题图

对于下面的4×4的矩阵,
  1 5 3 9
  3 7 5 6
  9 4 6 4
  7 3 1 3
  对其进行Z字形扫描后得到长度为16的序列:
  1 5 3 9 7 3 9 5 4 7 3 6 6 4 1 3
  请实现一个Z字形扫描的程序,给定一个n×n的矩阵,输出对这个矩阵进行Z字形扫描的结果。
输入格式
  输入的第一行包含一个整数n,表示矩阵的大小。
  输入的第二行到第n+1行每行包含n个正整数,由空格分隔,表示给定的矩阵。
输出格式
  输出一行,包含n×n个整数,由空格分隔,表示输入的矩阵经过Z字形扫描后的结果。
样例输入
4
1 5 3 9
3 7 5 6
9 4 6 4
7 3 1 3
样例输出
1 5 3 9 7 3 9 5 4 7 3 6 6 4 1 3
评测用例规模与约定
  1≤n≤500,矩阵元素为不超过1000的正整数。

对于一眼复杂且大的题目要考虑将其拆解成小问题并解决,比如题目中的箭头走向可能第一眼看上去无头绪,但是亲自体会箭头的走动后便可知此题目有规律可循。本题考察的是模拟

思路与注意项

  1. 箭头的下一步无非是4个方向,起点都是左上角到右下角。

  2. 观察箭头的转折点可以发现:在这里插入图片描述
    end就是走到了右下角,结束

  3. 向左下与向右上是主体部分,如果没有触碰到边界就沿此方向继续,触碰到就要判断下一步方向(根据第2步图,需要使用两个if判断),所以左下与右上需要使用循环while/for完成

  4. 画出n=2~5时的图,发现向左下的线条数为int LeftDn = n-1,向右上的线条数为: int RightUp = n-2

  5. 明确了遍历过程,那么设置开始时的位置,前两格是特殊的,会影响while内的遍历,故将其放在循环外面处理(注意:此时我遗漏了n=1的处理,导致第一次提交只有90分)
    在这里插入图片描述

  6. 考虑是否需要处理输入数据的区间端点,发现n=1时与第5步的处理冲突,需要单独处理(直接输出即可)。

代码

#include <iostream>

//1≤n≤500
using namespace std;

int pic[501][501];
int n;

bool canDown(int i){
	return ++i <= n;	
} 

bool canRight(int j){
	return ++j <= n;
}

bool canLeftDn(int i,int j){
	return ++i <= n && --j >= 1;
}

bool canRightUp(int i,int j){
	return --i >= 1 && ++j <= n;
}

int main(){
	cin >> n;
	for(int i = 1;i <= n;i++){
		for(int j = 1;j <= n;j++){
			cin>>pic[i][j];
		}
	}
	int LeftDn = n-1;
	int RightUp = n-2;
	
	int i=1;
	int j=2;
	//i=1,j=2是因为要从第一行第二列开始进入while循环
	if(n == 1){
		cout << pic[1][1];return 0;
	}
	cout<<pic[1][1]<<" "<<pic[1][2]<<" ";
	
	//循环终止条件为是否到达右下角
	while(!(i==n && j==n)){
		
		if(LeftDn){
			
			while(canLeftDn(i,j)){
				i++;j--;
				cout << pic[i][j] << " ";
			}
			LeftDn--;
			//这里注意向下和向右的优先级,能下就下,不能再右
			if(canDown(i)){
				i++;
				cout << pic[i][j] << " ";
			}
			else if(canRight(j)){
				j++;
				cout << pic[i][j] << " ";
			}
		} 
		
		//原理同向左上,注意向下和向右的优先级
		if(RightUp){
			while(canRightUp(i,j)){
				i--;j++;
				cout << pic[i][j] << " ";
			}
			RightUp--;
			if(canRight(j)){
				j++;
				cout << pic[i][j] << " ";
			} 
			else if(canDown(i)){
				i++;
				cout << pic[i][j] << " ";
			}
		} 
	}	
	return 0;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值