题解 | #[NOIP2017]棋盘#

[NOIP2017]棋盘

https://ac.nowcoder.com/acm/problem/16423

题目大意:

(1)从地图左上角走到右下角,不能斜着走
(2)有红、黄两种颜色的格子。相邻颜色格子,同颜色不用花钱,不同颜色要花1个金币
(3)遇到无颜色(白色)格子,可用一次魔法使其有红、黄中任意一种颜色,但不能连续使用。使用一次需花2个金币
(4)求出整个过程最小费用

思路分析:

(1)有图有格子,我们想到bfs(最为经典)
(2)**最关键的一点** :这和普通的bfs不同,并不是要找第一个到达终点的路线的费用,而是要找花费最少的费用,因此在到达终点后不能直接结束程序。这涉及到要多次访问同一个点,因此用一个数组val来存储每个点的最小花费,故称之为“记忆化搜索”。(上面的dalao也讲述过,本弱鸡只做通俗解释)
(3)bfs队列存储元素:x,y坐标、当前格子最小值、当前格子颜色。注意,由于可能出现多次访问某些点的情况,假若其中一些点无色,便会弄乱地图。因此我们要将每一步颜色存入对应的在队列中的位置,然后用原本的输入数组map记录原始的颜色
(4)bfs的判断条件:
		大条件:没有越界。
        1.当访问到的格子有颜色:
          跟新本点最小花费:是否更优解为上个点最小花费(val[beforex][beforey])加上每格花费
          val[nowx][nowy]=min(val[nowx][nowy], val[beforex][beforey]+abs(map[nowx][nowy]-map[beforex][beforey]))
          再存入队列即可
        2.当访问到的格子无颜色:
          若上个格子无颜色,则不成立(通过查看原始图map)
          否则:更新本点最小花费,类似于上面的
          val[nowx][nowy]=min(val[nowx][nowy],val[beforex][beforey]+2)
          再存入队列。注意存入颜色为上一个格子的颜色,因为这是贪心最优解(想想为什么)

易错指南:

本题用动态规划更新每个点很麻烦,因为本题在图上行走的方向可以是4个,而动态规划的一般适用于2个方向。

满分代码:

#include <cstdio>
#include <queue> 
#include <cmath>

using namespace std;

const int INF = 0x7ffffff;
const int N = 105;
struct T {
	int xp, yp, v, c;
	//x,y坐标,价格,颜色 
};

int m, n, x, y, c;
int a[N][N], val[N][N], ans = -1; 
// a数组存储原图,相当于前面说明的map
// val存储最小花费
int dx[4] = {1, -1, 0, 0};
int	dy[4] = {0, 0, 1, -1};
queue<T> Q;

void bfs() {
	val[1][1] = 0;
	Q.push(T{1, 1, 0, a[1][1]});
	while (!Q.empty()) {
		T head = Q.front();
		Q.pop();
		int bx = head.xp, by = head.yp;
		int bv = head.v, bc = head.c;
		// 上一个访问点的x,y坐标、最小花费和颜色
		for (int i = 0; i < 4; i++) {
			int cx = bx + dx[i];
			int cy = by + dy[i];
            // cx,cy为目前站在的点的x,y坐标
			if (cx > 0 && cy > 0 && cy <= m && cy <= m) {// 是否越界
				if (a[cx][cy]){
					if (val[cx][cy] > bv + abs(bc - a[cx][cy])) {// 更新最小花费
						val[cx][cy] = bv + abs(bc - a[cx][cy]);
						Q.push(T{cx, cy, val[cx][cy], a[cx][cy]});
					}
				}
				else {
					if (!a[bx][by]) continue ;
					if (val[cx][cy] > bv + 2) {// 同上
						val[cx][cy] = bv + 2;
						Q.push(T{cx, cy, val[cx][cy], bc});
					}
				}
			}
		}
	}
	if (val[m][m] != INF) ans = val[m][m];
    // 若能够到达终点
	return ;
}

int main() {
	scanf("%d %d", &m, &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d %d %d", &x, &y, &c);
		a[x][y] = c + 1;
	}
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j <= m; j++) {
			val[i][j] = INF;
		}
	}
	
	bfs();
	
	printf("%d", ans);
}

写在最后:

这篇题解是本弱鸡写的第一篇题解,望各位大佬帮忙指点指点,同时也希望大家多多鼓励,谢谢!
全部评论

相关推荐

赛博小保安:你这简历没啥大问题的,经历技能也足够了,问题应该就是出在出身了,学院本就是这样,HR忙着跟92的勾搭呢,哪有心思看我们这些双非😿😭
点赞 评论 收藏
分享
头像
10-22 20:13
中南大学 Java
序言大家好呀。我是希晨er,一个初入职场的程序猿小登最近上班摸鱼刷到了一篇文章:10年深漂,放弃高薪,回长沙一年有感,还有聊聊30岁大龄程序员过往的心路历程,突然就有点感慨。我如今也做出了和大明哥一样的抉择,只是更早。此外我22年的人生,好像从来没好好记录过。正好现在工作不太忙,就想把这些经历写下来,也希望能得到社区里各位前辈的指点个人背景我是03年出生的西安娃,父母都是普通打工人。刚从中南大学软件工程专业毕业半年,现在在老家的央企过着躺平摆烂的日子成长轨迹从农村到城市的童年我家并不是西安的,只是爸妈在西安上班,从小学之后就把我接到了西安。后来老家房子拆了,爷爷奶奶也搬了过来。农村的生活,我觉...
Yki_:看哭了,恋爱那一段你女朋友说你不够关心她,可你毕竟也愿意遇到矛盾写几千字来和她慢慢分析;说不愿意给她花钱,我感觉可能只是消费观不一样;如果她想留在长沙,也应该提前跟你说开。不过她也许会心疼你放弃大厂offer转向数字马力?我也因为同样的原因有过一段幸福而充满遗憾的感情,不过跟爱情相比确实前途更重要一点。至于offer的选择,换我我也会这么选。把这些旧事记录下来以后,接下来就好好向前看吧,加油兄弟
🍊晨光随笔
点赞 评论 收藏
分享
评论
3
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务