[C/C++/easyx]第十届蓝桥杯大赛软件类决赛-试题 G: 估计人数(easyx图形化演示)

【问题描述】
给定一个 N × M 的方格矩阵,矩阵中每个方格标记 0 或者 1 代表这个方格
是不是有人踩过。
已知一个人可能从任意方格开始,之后每一步只能向右或者向下走一格。
走了若干步之后,这个人可以离开矩阵。这个人经过的方格都会被标记为 1,
包括开始和结束的方格。注意开始和结束的方格不需要一定在矩阵边缘。
请你计算至少有多少人在矩阵上走过。
【输入格式】
输入第一行包含两个整数 N、M。
以下 N 行每行包含 M 个整数 (0/1),代表方格矩阵。
【输出格式】
输出一个整数代表答案。
【样例输入】
5 5
00100
11111
00100
11111
00100
【样例输出】
3
试题 G: 估计人数 10
【数据规模与约定】
对于所有评测用例,1 ≤ N, M ≤ 20,标记为 1 的方格不超过 200 个。

(gif图中,红色为广度优先搜索的路径,绿色为最终确立的最长有效路径,蓝色是可行走的路块)
在这里插入图片描述

本题使用C语言解题,读者可通过解除下列代码中第三行的注释符号并编译运行以获得该程序的图形化演示。

注意,graphics.h是C++语言的第三方库(easyx库),如要图形化演示,请配置相应头文件。

本题的解决思路是建立一个队列后,遍历map,并用最左上方的map值为1的点作为开始点,然后用广度优先搜索算法来遍历行走出来的最长路径,并记录之中的有效点的数量(map的元素中点值为’1’的点)。

其中拥有最多有效点的一条已被探明的完整路径将代表一个人走过这样的一条路径,同时,map的元素中在此路径上的点值均变成’2’,以表示该路仍可行走,但已“失效”。

在找到一个人后,再次寻找一个最左上方的map值为1的点作为开始点,重复上面步骤。
直至,无法再找一个最左上方的map值为1的点作为开始点,结束遍历。

此时,找到的所有人的数量就是至少有多少人在矩阵上走过的答案。

#include <stdio.h>
#include <stdlib.h>
//#define DEBUG
#ifdef DEBUG
#include <graphics.h>
#define BLOCK_WIDTH (10)
#define WAIT_TIME (500)
#endif // DEBUG

int N, M;
int people;
char **map;
struct BLOCK {
	int x;
	int y;
	int goodSet;//经过的有效点个数
	BLOCK *lastp;//队列的上一个点
	BLOCK *nextp;//队列的下一个点
	BLOCK *lastPointp;//当前路径的上个点
}*mostheadp,*headp, *endp;//队列的起始点,当前队列头结点,当前队列尾结点
void createQueue() {//创建队列
	mostheadp = (BLOCK*)malloc(sizeof(BLOCK));
	endp = headp = mostheadp;
	endp->x = endp->y = endp->goodSet = 0;
	endp->lastp = endp->nextp = endp->lastPointp = NULL;
}
void deleteQueue() {//删除队列:回收队列内存
	mostheadp = endp;
	while (mostheadp = mostheadp->lastp) {
		free(endp);
		endp = mostheadp;
	}
	free(endp);
}
void push(int x, int y, BLOCK *lastPointp) {//入列
	BLOCK *nowp = (BLOCK*)malloc(sizeof(BLOCK));
	nowp->x = x;
	nowp->y = y;
	nowp->lastp = endp;
	nowp->nextp = NULL;
	nowp->lastPointp = lastPointp;
	endp->nextp = nowp;
	endp = nowp;
	if (lastPointp) {//作为继承点
		nowp->goodSet = lastPointp->goodSet;
		if (map[y][x] == '1')//要走的格子没有被走过
			++nowp->goodSet;
	}
	else {//作为开始点
		nowp->goodSet = 1;
	}
}
void pop(BLOCK **nowp) {//出列
	headp = headp->nextp;
	*nowp = headp;
}

bool check(int x, int y) {//检查该点是否可走
	if (x >= 0 && x < M&&y >= 0 && y < N) {
		if (map[y][x] > '0')
			return true;
	}
	return false;
}
#ifdef DEBUG
void print() {//输出map的图形化表示
	int i, j;
	for (i = 0; i < N; ++i)
		for (j = 0; j < M; ++j) {
			switch (map[i][j]) {
			case '0':setfillcolor(WHITE); break;
			case '1':setfillcolor(LIGHTBLUE); break;
			case '2':setfillcolor(LIGHTGREEN); break;
			}
			fillrectangle(j*BLOCK_WIDTH, i*BLOCK_WIDTH, (j + 1)*BLOCK_WIDTH, (i + 1)*BLOCK_WIDTH);
		}
	Sleep(WAIT_TIME);
}
#endif // DEBUG

void start() {
	createQueue();//创建队列

	int i, j;
	for (i = 0; i < N; ++i) {
		for (j = 0; j < M; ++j) {//遍历所有点,以寻找开始点
			if (map[i][j] > '0') {//发现可以走的路
				if (map[i][j] == '1') {//如果这格路未走过,则可以作为开始点
					push(j, i, NULL);//放置开始点
					struct BLOCK *nowp;
					struct BLOCK *goodSetp = NULL;//存储一条经过的有效点(值为1的块)最多的路径
					while (headp->nextp) {//队列里有东西就一直继续,直至队列被清空,即可行路径搜索完毕
						pop(&nowp);//开始广度优先搜索
#ifdef DEBUG
						setfillcolor(LIGHTRED);
						fillrectangle(nowp->x*BLOCK_WIDTH, nowp->y*BLOCK_WIDTH, (nowp->x + 1)*BLOCK_WIDTH, (nowp->y + 1)*BLOCK_WIDTH);
						Sleep(WAIT_TIME);
#endif // DEBUG
						if (goodSetp) {
							if (goodSetp->goodSet < nowp->goodSet)
								goodSetp = nowp;
						}
						else
							goodSetp = nowp;
						//向右走
						if (check(nowp->x + 1, nowp->y)) {//右面一格可以走
							push(nowp->x + 1, nowp->y, nowp);
						}
						//向下走
						if (check(nowp->x, nowp->y + 1)) {//下面一格可以走
							push(nowp->x, nowp->y + 1, nowp);
						}
					}
					++people;
					while (goodSetp) {
						map[goodSetp->y][goodSetp->x] = '2';
						goodSetp = goodSetp->lastPointp; 
#ifdef DEBUG
						print();
#endif // DEBUG
					}
				}
			}
		}
	}

	printf("至少%d人", people);
	deleteQueue();//删除队列
}
int main() {
	int i;
	//数据载入
	scanf_s("%d%d", &N, &M);
	map = (char**)malloc(sizeof(char*)*N);
	for (i = 0; i < N; ++i) {
		map[i] = (char*)malloc(sizeof(char)*(M + 1));
		scanf_s("%s", map[i], M + 1);
	}
#ifdef DEBUG
	initgraph(BLOCK_WIDTH * N, BLOCK_WIDTH * M);
	setbkcolor(WHITE);
	cleardevice();
	setlinecolor(BLACK);
	print();
#endif // DEBUG

	start();

#ifdef DEBUG
	Sleep(3000);
	closegraph();
#endif // DEBUG

	//回收内存
	for (i = 0; i < N; ++i) 
		free(map[i]);
	free(map);
	return 0;
}

纯C运行结果
在这里插入图片描述

map的图形化演示运行结果(C++/easyx)
gif图中,红色为广度优先搜索的路径,绿色为最终确立的最长有效路径,蓝色是可行走的路块。
其中,红色由起点蔓延至终点(探索),绿色由终点蔓延到起点(回溯)。
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值