CSP-J 2022 入门级 第一轮 完善程序(2) 第40-44题

【题目】

CSP-J 2022 入门级 第一轮 完善程序(2) 第40-44题
(2 )(洪水填充) 现有用字符标记像素颜色的 8x8 图像。颜色填充的操作描述如下:给定起始像素的位置和待填充的颜色,将起始像素和所有可达的像素(可达的定义:经过 一次或多次的向上、下、左、右四个方向移动所能到达且终点和路径上所有像素的颜色都与起始像素颜色相同),替换为给定的颜色。
试补全程序。

01 #include <bits/stdc++.h>
02 using namespace std;
03
04 const int ROWS = 8;
05 const int COLS = 8;
06
07 struct Point {
08     int r, c;
09     Point(int r, int c) : r(r), c(c) {}
10 };
11
12 bool is_valid(char image[ROWS][COLS], Point pt,
13     int prev_color, int new_color) {
14     int r = pt.r;
15     int c = pt.c;
16     return (0 <= r && r < ROWS && 0 <= c && c < COLS &&
17&& image[r][c] != new_color);
18 }
19
20 void flood_fill(char image[ROWS][COLS], Point cur, int new_color) {
21     queue<Point> queue;
22     queue.push(cur);
23
24     int prev_color = image[cur.r][cur.c];
25;
26
27     while (!queue.empty()) {
28         Point pt = queue.front();
29         queue.pop();
30
31         Point points[4] = {, Point(pt.r - 1, pt.c),
32         Point(pt.r, pt.c + 1), Point(pt.r, pt.c - 1)};
33         for (auto p : points) {
34             if (is_valid(image, p, prev_color, new_color)) {
35;
36;
37             }
38         }
39     }
40 }
41
42 int main() {
43     char image[ROWS][COLS] = {{'g', 'g', 'g', 'g', 'g', 'g', 'g', 'g'},
44     {'g', 'g', 'g', 'g', 'g', 'g', 'r', 'r'},
45     {'g', 'r', 'r', 'g', 'g', 'r', 'g', 'g'},
46     {'g', 'b', 'b', 'b', 'b', 'r', 'g', 'r'},
47     {'g', 'g', 'g', 'b', 'b', 'r', 'g', 'r'},
48     {'g', 'g', 'g', 'b', 'b', 'b', 'b', 'r'},
49     {'g', 'g', 'g', 'g', 'g', 'b', 'g', 'g'},
50     {'g', 'g', 'g', 'g', 'g', 'b', 'b', 'g'}};
51
52     Point cur(4, 4);
53     char new_color = 'y';
54
55     flood_fill(image, cur, new_color);
56
57     for (int r = 0; r < ROWS; r++) {
58         for (int c = 0; c < COLS; c++) {
59             cout << image[r][c] << " ";
60         }
61         cout << endl;
62     }
63 // 输出:
64 // g g g g g g g g
65 // g g g g g g r r
66 // g r r g g r g g
67 // g y y y y r g r
68 // g g g y y r g r
69 // g g g y y y y r
70 // g g g g g y g g
71 // g g g g g y y g
72
73     return 0;
74 }
  1. ①处应填( )
    A. image[r][c] == prev_color
    B. image[r][c] != prev_color
    C. image[r][c] == new_color
    D. image[r][c] != new_color
  2. ②处应填( )
    A. image[cur.r+1][cur.c] = new_color
    B. image[cur.r][cur.c] = new_color
    C. image[cur.r][cur.c+1] = new_color
    D. image[cur.r][cur.c] = prev_color
  3. ③处应填( )
    A. Point(pt.r, pt.c)
    B. Point(pt.r, pt.c+1)
    C. Point(pt.r+1, pt.c)
    D. Point(pt.r+1, pt.c+1)
  4. ④处应填( )
    A. prev_color = image[p.r][p.c]
    B. new_color = image[p.r][p.c]
    C. image[p.r][p.c] = prev_color
    D. image[p.r][p.c] = new_color
  5. ⑤处应填( )
    A. queue.push( p )
    B. queue.push(pt)
    C. queue.push(cur)
    D. queue.push(Point(ROWS,COLS))

【题目考点】

1. 广搜 连通块问题

2. auto关键字

使用auto关键字可以让编译器自动确定声明的变量的类型。
例:auto p = 3.2(auto在这里相当于double)
例:vector vec; auto it = vec.begin();(auto在这里相当于vector::iterator)

3. for冒号

遍历一个可迭代对象中的所有元素。可迭代对象可以为:数组或vector、list等stl容器。
for(元素类型 变量名 : 可迭代对象)
元素类型为可迭代对象中元素的类型。可以写auto来自动设置元素类型。
取到的变量是值,改变该变量不会改变可迭代对象中元素的值。
for(元素类型 &变量名 : 可迭代对象)
取到的变量是引用,改变该变量会改变可迭代对象中元素的值。

【解题思路】

读题就能想到,该题是连通块问题。看代码可知,题目使用了广搜算法。

04 const int ROWS = 8;
05 const int COLS = 8;
06
07 struct Point {
08     int r, c;
09     Point(int r, int c) : r(r), c(c) {}
10 };

ROWS是行数,COLS是列数,Point类定义一个点,r是行号,c是列号。
Point(int r, int c):r(r),c(c){}是构造函数成员初始化列表的写法,意思是在调用构造函数时,将传入的第一个参数赋值给成员变量r,第二个参数赋值给成员变量c。

接下来的is_valid函数在调用时再看。

20 void flood_fill(char image[ROWS][COLS], Point cur, int new_color) {
21     queue<Point> queue;
22     queue.push(cur);
23
24     int prev_color = image[cur.r][cur.c];
25;
26

函数名是:洪水填充,看函数内的结构就能看出用了广搜算法。
先设队列,而后初始结点入队。
cur是起始位置,prev_color就是起始位置的颜色。
该题要做的是将包含起始位置的连通块的颜色从原颜色(prev_color)变为新颜色(new_color)。
初始位置已经入队了,初始位置应该改变颜色。
看第②空(第41题),可知这里要写的是使初始位置改变颜色,初始位置是(cur.r, cur.c),所以应该写:image[cur.r][cur.c] = new_color,选B。

27     while (!queue.empty()) {
28         Point pt = queue.front();
29         queue.pop();
30
31         Point points[4] = {, Point(pt.r - 1, pt.c),
32         Point(pt.r, pt.c + 1), Point(pt.r, pt.c - 1)};
33         for (auto p : points) {
34             if (is_valid(image, p, prev_color, new_color)) {
35;
36;
37             }
38         }
39     }
40 }

接着开始循环,只要队列不空,每次循环出队一个位置pt。接下来确定pt位置上下左右的四个位置,保存在points数组中。
Point(pt.r - 1, pt.c)是pt上方位置
Point(pt.r, pt.c + 1)是pt右侧位置
Point(pt.r, pt.c - 1)是pt左侧位置
还缺下方位置,应该是Point(pt.r+1, pt.c)。
第③空第42题应该选C。
接下来遍历points数组,这里用到了for冒号的写法,遍历points数组中的每个元素。
在循环内,先判断pt位置是否合法,判断函数为is_valid

12 bool is_valid(char image[ROWS][COLS], Point pt,
13     int prev_color, int new_color) {
14     int r = pt.r;
15     int c = pt.c;
16     return (0 <= r && r < ROWS && 0 <= c && c < COLS &&
17&& image[r][c] != new_color);
18 }

传入的image为图像二维数组,pt为被判断是否合法的位置,prev_color为起始位置颜色,new_color为要改变为的新颜色。
这里r,c为pt的行号和列号,首先0 <= r && r < ROWS && 0 <= c && c < COLS判断pt位置需要在地图内,image[r][c] != new_color表示新位置的颜色应该不与新颜色相同(如果与新颜色相同,说明这里已经变色了),还差一点需要填空。由于要把与起始位置颜色相同的在同一连通块内的位置都变色,因此这里需要与起始位置颜色相同,才是合法的,才需要进行变色。所以①这里应该填image[r][c] == prev_color,第40题选A。

33         for (auto p : points) {
34             if (is_valid(image, p, prev_color, new_color)) {
35;
36;
37             }
38         }

回到这里,如果该位置合法,那么按照广搜模板,这里应该访问p位置,然后pt位置入队。
这里所谓的访问,应该是将p位置设为新颜色:image[p.r][p.c] = new_color,第④空第43题选D。
而后把新位置p入队:que.push(p),第44题选A。

【答案】

  1. A
  2. B
  3. C
  4. D
  5. A

你可能感兴趣的:(初赛题解,初赛)