洛谷 P3956 [NOIP2017 普及组] 棋盘

2024-04-07 06:52

本文主要是介绍洛谷 P3956 [NOIP2017 普及组] 棋盘,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

思路:优先队列

其实本来想用双端队列进行解答的,但是呢,题目中有一个比较特殊的地方,那就是可以施展魔法让没有颜色的格子变成有颜色的格子,这样的话你如果普通的按照双端队列那样存储,会得不偿失,因为你将面临两个问题:何时才能涂颜色?涂颜色应该涂什么颜色最好呢?所以pass。

这里看了题解才知道要用优先队列进行优化。先从最折磨人的施展魔法这里讲起吧......

这个魔法问题,我们其实可以转化连续跳两个格子而代价为2的问题。

参照一个大佬的图像来讲解,也就是蓝色的格子就是我们施展魔法之后走到的格子,也就是连续跳2个格子。跳两个格子的含义我们知道了,但是代价为什么是2呢?有没有可能是3呢?不,我们考虑的就是最优情况,也就是说,我们跳这几个格子之后,自认为绿色的格子就是与蓝色的格子相同的颜色。

好,这个问题解决之后,我们需要知道为什么要用优先队列来处理?我们知道,优先队列是对存储的数值的某个属性从大到小排序的,我们这里需要用最小代价,所以可以改正优先队列的排序顺序,让它以最小代价为top。也就是堆的顺序改一下。

OK,这样还没完,终点我们需要特判一下,终点可能没有颜色呢?终点只能由它的上方走来,或者左方走来,那么得判断这两个方位的dist代价值哪一个小了,然后+2,因为需要涂色终点才能走。OK,这样我们需要知道这个时候这个值为多少,如果是大于初始值,那么也就是说到达终点的必经之路都没有涂色,而终点也没有涂色,意味着我们需要连续涂色两次,我们就认为这是不能到达的,魔法不能重复使用。

终点有颜色的情况我们也需要知道,也就是说,如果有颜色但是dist的值还是初始值,证明没有遍历到它,也就是不能到达。

上代码:

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<cmath> 
#include<vector>
#include<algorithm>
#include<stack>
#include<queue>
#include<deque>
#include <iomanip>
#include<sstream>
#include<numeric>
#include<map>
#include<limits.h>
#include<unordered_map>
#include<set>
#define int long long
#define MAX 505
#define inf 0x3f3f3f3f
#define _for(i,a,b) for(int i=a;i<(b);i++)
#define ALL(x) x.begin(),x.end()
using namespace std;
typedef pair<int, int> PII;
int n, m;
int counts;
int dx[] = { 0,1,0,-1,1,1,-1,-1,0,2,0,-2 };//12方向及魔法代价 
int dy[] = { 1,0,-1,0,1,-1,1,-1,2,0,-2,0 };
int dw[] = { 0,0,0,0,2,2,2,2,2,2,2,2 };//在上下左右的时候,代价手算,如果方块颜色相同,就不变,不同再+1
struct node {int x;int y;int c;//颜色int w;//代价bool operator <(node b)const {return w > b.w;//优先队列因为是把代价从大到小排列的,所以我们需要改变一下,改成从小到大。}
};
priority_queue<node>q;
int maps[MAX][MAX];//存储原先地图里面的颜色
int dist[MAX][MAX];//用来记录每个格子的最优代价
void bfs() {memset(dist, 0x3f, sizeof dist);dist[1][1] = 0;q.push({ 1,1,maps[1][1],dist[1][1] });node d;while (!q.empty()) {auto tmp = q.top();q.pop();if (dist[tmp.x][tmp.y] < tmp.w)//如果说dist已经比现在这个遍历的格子要代价小了continue;_for(i, 0, 12) {//遍历d.x = dx[i] + tmp.x;d.y = dy[i] + tmp.y;d.w = dw[i] + tmp.w;if (d.x > n || d.x < 1 || d.y<1 || d.y>n)//边界处理continue;d.c = maps[d.x][d.y];if (!d.c)//如果说是无色,那就继续(在后面我们把颜色的数值都加了1,这样方便判断无色continue;if (tmp.c != d.c)d.w++;//颜色不同的时候代价+1if (dist[d.x][d.y] > d.w) {dist[d.x][d.y] = d.w;//这个时候遍历的格子是最优解q.push(d);}}}}
signed main() {ios::sync_with_stdio(false);cin.tie(NULL); cout.tie(NULL);cin >> n >> m;_for(i, 1, m + 1) {int x;int y;int c;cin >> x >> y >> c;maps[x][y] = c+1;}bfs();if (!maps[n][n]) {//判断最后一个格子是不是有颜色int res = min(dist[n - 1][n], dist[n][n - 1]) + 2;//这里因为if (res >= inf)cout << -1 << endl;elsecout << res << endl;}else {if (dist[n][n] >= inf)//终点没有遍历到,也就是没有到达cout << -1 << endl;elsecout << dist[n][n] << endl;}return 0;
}

这篇关于洛谷 P3956 [NOIP2017 普及组] 棋盘的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/881920

相关文章

洛谷 P10584 [蓝桥杯 2024 国 A] 数学题(整除分块+杜教筛)

题目 思路来源 登录 - Luogu Spilopelia 题解 参考了两篇洛谷题解,第一篇能得出这个式子,第二篇有比较严格的复杂度分析 结合去年蓝桥杯洛谷P9238,基本就能得出这题的正确做法 代码 #include<bits/stdc++.h>#include<iostream>#include<cstdio>#include<map>#include<uno

洛谷P8502题解

[problem] \color{blue}{\texttt{[problem]}} [problem] [Solution] \color{blue}{\texttt{[Solution]}} [Solution] 这题最恶心的地方是卡空间。 我们先考虑不卡空间时怎么做。 直接并不好做,我们考虑正难则反,即利用容斥原理。答案应为从 a a a 没有任何限制经过 m m m 条

洛谷:P1085 [NOIP2004 普及组] 不高兴的津津

1. 题目链接 https://www.luogu.com.cn/problem/P1085 P1085 [NOIP2004 普及组] 不高兴的津津 2. 题目描述 题目描述:津津每天要上课还要上辅导班,每天学习超过8小时就不开心,帮忙检查下津津的下周日程安排,然后告诉我她哪天不高兴 输入:7行数据,每行2个小于10的非负整数,分别代表在学校的时间和辅导班的时间 输出:哪天最不高兴,如果有

【洛谷P3366】【模板】最小生成树 解题报告

洛谷P3366 -【模板】最小生成树 题目描述 如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz。 输入格式 第一行包含两个整数 N , M N,M N,M,表示该图共有 N N N 个结点和 M M M 条无向边。 接下来 M M M 行每行包含三个整数 X i , Y i , Z i X_i,Y_i,Z_i Xi​,Yi​,Zi​,表示有一条长度为 Z

洛谷:P5714 【深基3.例7】肥胖问题

1. 题目链接 https://www.luogu.com.cn/problem/P5714 P5714 【深基3.例7】肥胖问题 2. 题目描述 题目描述:BMI计算:m / (h * h),m是体重(kg),h是身高(m) 小于18.5:体重国轻,Underweight 小于等于18.5且小于24:正常,Normal 大于等于24:肥胖,不仅要输出BMI值,换行,输出Overweigh

Matlab 单目相机标定(内置函数,棋盘格)

文章目录 一、简介二、实现代码三、实现效果参考资料 一、简介 具体的标定原理可以参阅之前的博客Matlab 单目相机标定(内置函数),这里实现对棋盘格数据的标定过程。 二、实现代码 getCameraCorners.m function [camCorners, usedImIdx, imCheckerboard] = getCameraCorners(cali

头歌资源库(14)残缺棋盘

一、 问题描述  二、算法思想   首先,将2^k × 2^k的棋盘划分为四个相等大小的子棋盘,定义为左上、左下、右上和右下四个子棋盘。 然后,根据残缺格的坐标,确定其中一个子棋盘是不完整的,即残缺子棋盘。假设残缺子棋盘是左上子棋盘。 接下来,分以下三种情况进行处理: 当k=1时,即棋盘大小为2×2时,直接填充序号即可。 当残缺子棋盘的坐标位于左上子棋盘的右下角时,将左上子棋盘的

洛谷 P1141 01迷宫 (dfs解决)

题目描述 有一个仅由数字 0 与 1 组成的 n×n 格迷宫。若你位于一格 0 上,那么你可以移动到相邻 4 格中的某一格 1 上,同样若你位于一格 1 上,那么你可以移动到相邻 4 格中的某一格 0 上。 你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。 输入格式 第一行为两个正整数 𝑛,𝑚。 下面 𝑛 行,每行 𝑛 个字符,字符只可能是 0 或者

【洛谷P3374 P3368】树状数组

提示 本文只记录模板,不做详细解释 P3374 树状数组1 原题链接 #include <iostream>#define lowbit(x) x&(-x)#define N 5*(int)1e5+1using namespace std;int n,m,num[N];long long tree[N];void add(int idx,int val){while(idx<=

【洛谷P2054洗牌】AC代码(扩展欧几里得+二分快速幂+二分龟速乘)

题目描述 题目链接 为了表彰小联为Samuel星球的探险所做出的贡献,小联被邀请参加Samuel星球近距离载人探险活动。 由于Samuel星球相当遥远,科学家们要在飞船中度过相当长的一段时间,小联提议用扑克牌打发长途旅行中的无聊时间。玩了几局之后,大家觉得单纯玩扑克牌对于像他们这样的高智商人才来说太简单了。有人提出了扑克牌的一种新的玩法。 对于扑克牌的一次洗牌是这样定义的,将一叠N(N为偶数