CCF CSP认证 历年真题自练Day42

题目

试题编号: 201512-3

试题名称: 画图

时间限制: 1.0s

内存限制: 256.0MB

问题描述:

问题描述

用 ASCII 字符来画图是一件有趣的事情,并形成了一门被称为 ASCII Art 的艺术。例如,下图是用 ASCII 字符画出来的 CSPRO 字样。

.... ...... ......
  ./.
/.||....|....../. ...

|.|..._.|.|).|.| ).|.|.|.|
  |.|
. ).|... /|....<|.| |.|

.| /| |...|*|.\* __/.

本题要求编程实现一个用 ASCII 字符来画图的程序,支持以下两种操作:

Ÿ 画线:给出两个端点的坐标,画一条连接这两个端点的线段。简便起见题目保证要画的每条线段都是水平或者竖直的。水平线段用字符 - 来画,竖直线段用字符 | 来画。如果一条水平线段和一条竖直线段在某个位置相交,则相交位置用字符 + 代替。

Ÿ 填充:给出填充的起始位置坐标和需要填充的字符,从起始位置开始,用该字符填充相邻位置,直到遇到画布边缘或已经画好的线段。注意这里的相邻位置只需要考虑上下左右 4 个方向,如下图所示,字符 @ 只和 4 个字符 * 相邻。

..
  @
  .
.

输入格式

第1行有三个整数m, n和q。m和n分别表示画布的宽度和高度,以字符为单位。q表示画图操作的个数。

第2行至第q + 1行,每行是以下两种形式之一:

Ÿ 0 x1 y1 x2 y2:表示画线段的操作,(x1, y1)和(x2, y2)分别是线段的两端,满足要么x1 = x2 且y1 ≠ y2,要么 y1 = y2 且 x1 ≠ x2。

Ÿ 1 x y c:表示填充操作,(x, y)是起始位置,保证不会落在任何已有的线段上;c 为填充字符,是大小写字母。

画布的左下角是坐标为 (0, 0) 的位置,向右为x坐标增大的方向,向上为y坐标增大的方向。这q个操作按照数据给出的顺序依次执行。画布最初时所有位置都是字符 .(小数点)。

输出格式

输出有n行,每行m个字符,表示依次执行这q个操作后得到的画图结果。

样例输入

4 2 3

1 0 0 B

0 1 0 2 0

1 0 0 A

样例输出

AAAA

A--A

样例输入

16 13 9

0 3 1 12 1

0 12 1 12 3

0 12 3 6 3

0 6 3 6 9

0 6 9 12 9

0 12 9 12 11

0 12 11 3 11

0 3 11 3 1

1 4 2 C

样例输出

...

...±-------+...

...|CCCCCCCC|...

...|CC±----+...

...|CC|...

...|CC|...

...|CC|...

...|CC|...

...|CC|...

...|CC±----+...

...|CCCCCCCC|...

...±-------+...

...

评测用例规模与约定

所有的评测用例满足:2 ≤ m, n ≤ 100,0 ≤ q ≤ 100,0 ≤ x < m(x表示输入数据中所有位置的x坐标),0 ≤ y < n(y表示输入数据中所有位置的y坐标)。

题目分析

  1. 首先还是先看题目,它要实现两个功能,第一个是画线,第二个是填充。如何判断到底是划线还是填充呢?首先是看第二行到第q+1行的第一个字符是0还是1?如果是0就表示划线,如果是1就表示填充操作。
  2. 首先呢先建立一个宽为m,高为n的画布。我先将这个画布全部用点来表示每一个坐标。注意,题目中提到的左下角的坐标是(0,0)。 那我还是可以用二维列表去表示画布。只需要将最后的画布倒序输出二维列表的每一个一纬元素(列表)即可。
  3. 创建画布的具体方法可以用列表推导式。然后再进行对画布到底是画线操作还是填充操作进行判断,如果是划线操作,那么注意在横竖交接的地方使用+替代。如何具体实现呢?可以进行一步判断,如果此坐标位置在画横线的步骤中出现了画竖线的标识那么就用+替代,如果此位置坐标位置在画竖线的位置中出现了画横线的标识,也用+替代即可。
  4. 对于填充的操作,可以先设置一个函数,然后利用递归的思想实现遇到边缘或有横线和竖线的坐标停止。那么填充在函数的具体方法是什么?它只填充上下左右四个方向的坐标。可以先将当前位置的左上,右下坐标分别存储在列表。然后对坐标遍历此列表即可得到需要填充的坐标的上下左右四个坐标,然后对这四个坐标进行判断,是否超出了画布的大小,或者已经存在横竖的标识符。如果是,则跳出循环。如果不是,则利用递归的思想在函数体内调用函数(自身)。
  5. 上代码!!!但是只有90分不知道为啥。。。麻烦大佬找到问题评论区评论,呜呜呜。
python 复制代码
direct = [[-1,0],[1,0],[0,-1],[0,1]]
m, n, q = map(int, input().split())
grid = [['.' for _ in range(m)] for _ in range(n)]
#设置填充函数
def fill(x, y, c, m, n):
    grid[y][x] = c
    for i in direct:
        nx = x + i[0]
        ny = y + i[1]
        if 0 <= nx < m and 0 <= ny < n and grid[ny][nx] not in ['|', '-', '+', c]:
            fill(nx, ny, c, m, n)
# 处理q个画图操作
for _ in range(q):
    # 输入形式
    option = input().split()
    if option[0]== '0':
        # 输入坐标
        x1, y1, x2, y2 = int(option[1]),int(option[2]),int(option[3]),int(option[4])

        # 画线
        if x1 == x2:
            start = min(y1, y2)
            end = max(y1, y2)
            for j in range(start, end+1):
                if grid[j][x1] in ['-','+']:
                    grid[j][x1] = '+'
                else:
                    grid[j][x1] = '|'
        elif y1 == y2:
            start = min(x1, x2)
            end = max(x1, x2)
            for j in range(start, end+1):
                if grid[y1][j] in ['|','+']:
                    grid[y1][j] = '+'
                else:
                    grid[y1][j] = '-'
    elif option[0] == '1':
        # 输入填充的坐标和字符
        x1, y1, c = int(option[1]), int(option[2]), option[3]

        # 递归填充
        fill(x1, y1, c, m, n)

# 输出结果
for row in reversed(grid):
    print(''.join(row))

总结

为什么?这究竟是为什么?!

相关推荐
学会沉淀。8 分钟前
Docker学习
java·开发语言·学习
如若1239 分钟前
对文件内的文件名生成目录,方便查阅
java·前端·python
Rinai_R23 分钟前
计算机组成原理的学习笔记(7)-- 存储器·其二 容量扩展/多模块存储系统/外存/Cache/虚拟存储器
笔记·物联网·学习
吃着火锅x唱着歌23 分钟前
PHP7内核剖析 学习笔记 第四章 内存管理(1)
android·笔记·学习
ragnwang25 分钟前
C++ Eigen常见的高级用法 [学习笔记]
c++·笔记·学习
西猫雷婶39 分钟前
python学opencv|读取图像(二十一)使用cv2.circle()绘制圆形进阶
开发语言·python·opencv
老刘莱国瑞1 小时前
STM32 与 AS608 指纹模块的调试与应用
python·物联网·阿里云
火星机器人life2 小时前
基于ceres优化的3d激光雷达开源算法
算法·3d
Web阿成2 小时前
3.学习webpack配置 尝试打包ts文件
前端·学习·webpack·typescript