CCFCSP认证 历年题目自练Day7

CCFCSP认证 历年题目自练Day7

CCFCSP认证 历年题目自练Day7

试题编号: 201412-2
试题名称: Z字形扫描
时间限制: 2.0s
内存限制: 256.0MB
问题描述:
问题描述
  在图像编码的算法中,需要将一个给定的方形矩阵进行Z字形扫描(Zigzag Scan)。给定一个n×n的矩阵,Z字形扫描的过程如下图所示:CCFCSP认证 历年题目自练Day7_第1张图片

对于下面的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. 先看输入,n是确定了正方形的边长。直接n=int(input())
  2. 接着输入矩阵的每一个坐标点的值。我选择用列表存(列表嵌套列表,类矩阵。)
s=[]
for i in range(n):
    s+=[list(map(int,input().split()))]
  1. 按照例子,此时,s=[[1539],[3796],[9464],[7313]]
  2. 现在考虑扫描的算法,只要按照算法依次提取出从s[0][0]到s[n-1][n-1]的元素就OK!
  3. 现在只考虑斜线方向,也就是从右上往左下扫描和从左下往右上扫描。(解决图中黑色线条的算法,然后再解决碰壁问题。最后把[0][0]和[n-1][n-1]加在最前面和最后面就OK!)

CCFCSP认证 历年题目自练Day7_第2张图片

  1. 行对应着列表s的第一个嵌套,列对应着s的第二个嵌套。先定义一个列表l用来存放按照算法的顺序排序的最后输出值。l=[s[0][0]]
    用x表示行,y表示列,我选择定义一个函数实现斜线方向移动遍历的功能。
    设置一个开关bl 当bl=1的时候斜向下扫描bl=-1的时候斜向上扫描。不难发现(0,1)位置始终先向下扫描,后面换方向扫描直到碰壁。
x=0;y=0#x是行y是列
def Z(x,y,number,bl):#斜向移动函数 bl=1从右上往左下bl=-1从左下到右上
    for i in range(number):
        x=x+bl
        y=y-bl
        l.append(s[x][y])
    bl=-bl
    return x,y,bl
  1. 解决碰壁问题:
    (1)斜向下碰左壁,x不变y加一。
    (2)斜向上碰上壁,y不变x加一。
    (3)此时左上部分的正方形遍历算法已经结束。
    (4)只看右下部分的正方形,此时碰右壁,x不变y加一。
    (5)碰下壁,y不变x加一。
  2. 问题来了,如何判断碰壁的位置?对于左上部分正方形,斜向下扫描碰壁只能是左壁,斜向上只能碰上壁。右下部分斜向下只能碰下壁,斜向上只能碰右壁。也就是用bl的值去判断走向即可。
  3. 最后把[0][0],[n-1][n-1]加在 l[] 的最前面和最后面即可。
  4. 上代码!!!
n=int(input())
s=[]
for i in range(n):
    s+=[list(map(int,input().split()))]
bl=1
l=[s[0][0]]
x=0;y=0#x是行y是列
def Z(x,y,number,bl):#斜向移动函数 bl=1从右上往左下bl=-1从左下到右上
    for i in range(number):
        x=x+bl
        y=y-bl
        l.append(s[x][y])
    bl=-bl
    return x,y,bl

for i in range(n-1):#循环结束移动到[0,n-1]#左下角
    if bl==1:
        y+=1
    else:
        x+=1
    l.append(s[x][y])
    x,y,bl=Z(x,y,i+1,bl)

for i in range(n-2):#剩下移动
    if bl==-1:
        y+=1
    else:
        x+=1
    l.append(s[x][y])
    x,y,bl=Z(x,y,n-i-2,bl)


l.append(s[n-1][n-1])#加上最后一点
print(l[0],end='')
for i in range(1,n*n):
    print('',l[i],end='')
  1. 别急,还有第二种方法!我T在这里插入图片描述
    哭死!
  2. 可以把扫描看为在n为无限大的表格上斜方向扫描,到底啥时候斜向下扫?啥时候斜向上扫?
  3. 大家仔细观察行序和列序,不难发现z字形扫描的规律可表述为:
    (1)斜向下扫描时,纵坐标从min(t, n-1),逐步减1,直至t - min(t, n-1)。这里,t为该扫描线任意单元格横坐标加上纵坐标之和。min(t, n-1)是取t和n-1的最小值的意思。
    (2)斜向上扫描时,横坐标从min(t, n-1),逐步减1,直至t - min(t, n-1)。这里,t为该扫描线任意单元格横坐标加上纵坐标之和。
    (3)t为奇数,是斜向下扫描。t为偶数,是斜向上扫描。

n = int(input())
n_mtx = []
for i in range(n):
    n_line = [int(s) for s in input().split()]
    n_mtx.append(n_line)
# print(n_mtx)

print(n_mtx[0][0], end = ' ')
max_xplusy = n - 1 + n - 1  #横坐标+纵坐标之和的最大值,也是右下角元素的横坐标+纵坐标之和
#沿斜线迭代n*n方阵mtx的元素,这些元素的横坐标+纵坐标=t
def itr(mtx, n, t):
    start = min(n-1, t)
    if t % 2 == 0:  #偶数,斜向上遍历
        for x in range(start, t - start - 1, -1):
            print(mtx[x][t-x], end = ' ')
    else:  #t为奇数,斜向下遍历
        for y in range(start, t - start - 1, -1):
            print(mtx[t-y][y], end = ' ')

for t in range(1, max_xplusy + 1):
    #遍历斜线上的元素
    itr(n_mtx, n, t)


总结

累!脑子要裂开!!!但是爽!
CCFCSP认证 历年题目自练Day7_第3张图片
CCFCSP认证 历年题目自练Day7_第4张图片
CCFCSP认证 历年题目自练Day7_第5张图片

你可能感兴趣的:(python,开发语言,学习)