◆竞赛题目◆◇NOIP 2017 普及组◇ Chess 棋盘
来源:互联网 发布:python 字符串相似度 编辑:程序博客网 时间:2024/06/07 05:33
◇NOIP 2017 普及组◇ Chess
Description
有一个m × m的棋盘,棋盘上每一个格子可能是红色、黄色或没有任何颜色的。你现在
要从棋盘的最左上角走到棋盘的最右下角。
任何一个时刻,你所站在的位置必须是有颜色的(不能是无色的),你只能向上、下、
左、右四个方向前进。当你从一个格子走向另一个格子时,如果两个格子的颜色相同,那你不需要花费金币;如果不同,则你需要花费1 个金币。
另外,你可以花费2 个金币施展魔法让下一个无色格子暂时变为你指定的颜色。但这个
魔法不能连续使用,而且这个魔法的持续时间很短,也就是说,如果你使用了这个魔法,走到了这个暂时有颜色的格子上,你就不能继续使用魔法;只有当你离开这个位置,走到一个本来就有颜色的格子上的时候,你才能继续使用这个魔法,而当你离开了这个位置(施展魔法使得变为有颜色的格子)时,这个格子恢复为无色。
现在你要从棋盘的最左上角,走到棋盘的最右下角,求花费的最少金币是多少?
Input
第一行包含两个正整数m,n,以一个空格分开,分别代表棋盘的大小,棋盘上
有颜色的格子的数量。
接下来的 n 行,每行三个正整数x,y,c,分别表示坐标为(x,y)的格子有颜色c。
其中c=1 代表黄色,c=0 代表红色。相邻两个数之间用一个空格隔开。棋盘左上角的坐标为(1, 1),右下角的坐标为(m, m)。
棋盘上其余的格子都是无色。保证棋盘的左上角,也就是(1,1)一定是有颜色的。
Output
输出一行,一个整数,表示花费的金币的最小值,如果无法到达,输出-1。
Sample Input
5 71 1 01 2 02 2 13 3 13 4 04 4 15 5 0
Sample Output
8
题目解析
这次NOIP一如既往,第三题还是考察搜索,唯一不一样的就是直接搜索似乎会超时……据一位大牛说,这道题本来考察的是广度优先搜索再加上一个优先队列优化,然而 —— 作者用了深度优先搜索,加上剪枝优化。
一、肯定先说作者自己的代码啊
这其实是一个迷宫问题,非要把它放在棋盘上……因此我们很容易想到用搜索解决迷宫问题。不知道为什么,我几乎想都没想就选择用深度优先搜索,而且凭借经验加上了一个判重。这个深度优先搜索没有什么特别的 —— 参数包含坐标
那么从简单的开始,不考虑使用魔法。常规的,我们用
memset(Flag,0,sizeof Flag);
如果当前的
接下来就是考虑使用魔法的情况 —— 这种情况只在下一步是空白格子时会产生。因此判断下一步的格子是否为空时,若是空白,则判断
许多同学问我:“题目说这样改变格子的颜色只是一瞬间,走过了就恢复为空白吗?为什么可以在整个搜索完毕后再回溯?”其原因是搜索中进行了剪枝,如果改变这个格子颜色再后走到这一格子,则
还有一个问题——“有红黄两种颜色,那么把下一步的格子改变为什么颜色最优呢?”答案是当前脚下的格子的颜色。由于我们改变格子颜色是为了能通过这一格子到达下一个格子,这里就分2种情况——
①当前格子和通过改变了颜色的格子所到达的下一个格子的颜色相同,即:
那么非常明显需要把中间的空白格子改为现在脚下的格子的颜色。
②当前格子和通过改变了颜色的格子所到达的下一个格子的颜色不相同,即:
如果改为红色,则从红色格子到黄色格子需要1金币;如果改为黄色,则从黄色格子到红色格子同样需要1金币……也就是说,这2种是一样的,不过考虑到统一性,也采用改为当前脚下的格子的颜色的方案。
二、然后说说某一位大牛的代码吧
总体的思路是相同的,只是在实现上采用了完全不同的方法。应对数据量庞大的迷宫问题往往要采用广度优先搜索,但是这道题还需要优先队列优化——用优先队列代替原来的FIFO队列。
框架与广度优先搜索完全一样,不一样的是代码中的
优先队列的类型是一个结构体
我感觉没有错的程序(应该不会
//Problem 3#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int n,Num_Color,chess[105][105];int Flag[105][105],F[4][2]={{0,1},{1,0},{0,-1},{-1,0}};void Search(int x,int y,int sum,bool use){ if(sum>=Flag[x][y]) return; Flag[x][y]=sum; for(int i=0;i<4;i++) { int sx=x+F[i][0],sy=y+F[i][1]; if(sx<1 || sy<1 || sx>n || sy>n) continue; if(chess[sx][sy]==-1) { if(!use) chess[sx][sy]=chess[x][y],Search(sx,sy,sum+2,true),chess[sx][sy]=-1; continue; } if(chess[sx][sy]==chess[x][y]) Search(sx,sy,sum,false); else Search(sx,sy,sum+1,false); }}int main(){ freopen("chess.in","r",stdin); freopen("chess.out","w",stdout); memset(chess,-1,sizeof chess); scanf("%d%d",&n,&Num_Color); for(int i=0,x,y,color;i<Num_Color;i++) scanf("%d%d%d",&x,&y,&color),chess[x][y]=color; memset(Flag,0x3f,sizeof Flag); const int Error=Flag[0][0]; Search(1,1,0,0); if(Error!=Flag[n][n]) printf("%d\n",Flag[n][n]); else printf("-1\n"); return 0;}
下面是某一位大牛的代码,是用的 广度优先搜索+优先队列 优化:
#include<cstdio>#include<cstring>#include<queue>using namespace std;const int MAXN = 100;const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};int a[MAXN+5][MAXN+5];int MIN[MAXN+5][MAXN+5][2];struct NODE{ int x,y,t,c;}p;bool operator<(NODE a,NODE b){ return a.t>b.t;}priority_queue<NODE>que;int main(){ freopen("chess.in","r",stdin); freopen("chess.out","w",stdout); memset(a,-1,sizeof(a)); memset(MIN,63,sizeof(MIN)); int m,n; scanf("%d %d",&m,&n); for(int i=1;i<=n;i++) { int x,y,c; scanf("%d %d %d",&x,&y,&c); a[x][y] = c; } p.x = 1;p.y = 1; p.t = 0;p.c = a[1][1]; MIN[1][1][a[1][1]] = 0; que.push(p); do { p = que.top();que.pop(); if( p.x == m && p.y == m ) { printf("%d\n",p.t); return 0; } if( p.t < MIN[p.x][p.y][p.c] ) continue; for(int i=0;i<4;i++) { NODE q; q.x = p.x + dir[i][0]; q.y = p.y + dir[i][1]; if( q.x < 1 || q.y < 1 || q.x > m || q.y > m ) continue; if( a[q.x][q.y] == -1 ) { if( a[p.x][p.y] == -1 ) continue; q.t = p.t + 2; q.c = p.c; if( q.t < MIN[q.x][q.y][q.c] ) { MIN[q.x][q.y][q.c] = q.t; que.push(q); } q.c = !(p.c); q.t++; if( q.t < MIN[q.x][q.y][q.c] ) { MIN[q.x][q.y][q.c] = q.t; que.push(q); } } else { q.t = p.t;q.c = a[q.x][q.y]; if( q.c != p.c ) q.t++; if( q.t < MIN[q.x][q.y][q.c] ) { MIN[q.x][q.y][q.c] = q.t; que.push(q); } } } }while(!que.empty()); printf("-1\n"); return 0;}
The End
Thanks for reading!
-Lucky_Glass
- ◆竞赛题目◆◇NOIP 2017 普及组◇ Chess 棋盘
- NOIP 2017 普及组 棋盘 chess
- 【NOIP普及组2017】棋盘Chess
- ◆竞赛题目◆◇NOIP 2017 普及组◇ 图书管理员
- ◆竞赛题目◆◇NOIP2015普及组◇求和
- ◆竞赛题目◆◇NOIP 2017◇ jump 跳房子
- 2017NOIp 普及组第三题 棋盘
- ◆竞赛题目◆◇NOIP2013普及组◇ 小朋友的数字
- ◆竞赛题目◆◇NOIP2016普及组◇ 魔法阵
- 2017年NOIP普及组第三题“chess”题解
- NOIP 1997 普及组 复赛 棋盘问题
- NOIP 2017 普及组 初赛
- 【NOIP 2017普及组】 成绩
- 【NOIP 2017普及组】 图书管理员
- [noip 2017]普及组 T1
- [noip 2017]普及组 T2
- [noip 2017]普及组 T3
- [noip 2017]普及组 T4
- nodejs模块nodemailer基本使用-邮件发送(支持附件)
- getX、getY与getRawX、getRawY的区别
- 计算机网络漫谈:OSI七层模型与TCP/IP四层(参考)模型
- select case when if 的一些用法
- LruCache原理分析整理
- ◆竞赛题目◆◇NOIP 2017 普及组◇ Chess 棋盘
- 微信小程序开发指南
- UCAS计算机网络实验
- 欢迎使用CSDN-markdown编辑器
- Maven本地安装和配置
- batch normalization的tensorflow实现
- 有关QT中声明一个vector为全局变量的初始化问题
- linux centos7安装nginx
- HTTP中GET和POST方法的区别