NOIP 2011 Senior 3
来源:互联网 发布:mac dashboard是什么 编辑:程序博客网 时间:2024/06/06 00:56
Mayan 游戏
总时间限制: 3000ms 内存限制: 65535kB
描述
Mayan puzzle 是最近流行起来的一个游戏。游戏界面是一个 7行 5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上。游戏通关是指在规定的步数内消除所有的方块,消除方块的规则如下:
1、 每步移动可以且仅可以沿横向(即向左或向右)拖动某一方块一格:当拖动这一方块时, 如果拖动后到达的位置 (以下称目标位置) 也有方块, 那么这两个方块将交换位置 (参见输入输出样例说明中的图 6 到图 7) ;如果目标位置上没有方块,那么被拖动的方块将从原来的竖列中抽出,并从目标位置上掉落(直到不悬空,参见下面图 1 和图2) ;
2、 任一时刻,如果在一横行或者竖列上有连续三个或者三个以上相同颜色的方块,则
它们将立即被消除(参见图 1 到图3) 。
注意:
a) 如果同时有多组方块满足消除条件,几组方块会同时被消除(例如下面图 4,三个颜色为 1 的方块和三个颜色为 2 的方块会同时被消除,最后剩下一个颜色为 2 的方块) 。
b) 当出现行和列都满足消除条件且行列共享某个方块时,行和列上满足消除条件的所有方块会被同时消除(例如下面图 5 所示的情形,5 个方块会同时被消除) 。
3、 方块消除之后,消除位置之上的方块将掉落,掉落后可能会引起新的方块消除。注意:掉落的过程中将不会有方块的消除。
上面图 1 到图 3 给出了在棋盘上移动一块方块之后棋盘的变化。 棋盘的左下角方块的坐标为(0, 0) ,将位于(3, 3)的方块向左移动之后,游戏界面从图 1 变成图 2 所示的状态,此时在一竖列上有连续三块颜色为 4 的方块,满足消除条件,消除连续 3块颜色为 4的方块后,上方的颜色为 3 的方块掉落,形成图 3 所示的局面。
输入
第一行为一个正整数 n,表示要求游戏通关的步数。
接下来的 5行,描述 7*5 的游戏界面。每行若干个整数,每两个整数之间用一个空格隔开,每行以一个 0 结束,自下向上表示每竖列方块的颜色编号(颜色不多于 10 种,从 1 开始顺序编号,相同数字表示相同颜色) 。
输入数据保证初始棋盘中没有可以消除的方块。
输出
如果有解决方案,输出 n 行,每行包含 3 个整数x,y,g,表示一次移动,每两个整数之间用一个空格隔开,其中(x,y)表示要移动的方块的坐标,g 表示移动的方向,1 表示向右移动,-1 表示向左移动。注意:多组解时,按照 x 为第一关健字,y 为第二关健字,1优先于-1,给出一组字典序最小的解。游戏界面左下角的坐标为(0,0) 。
如果没有解决方案,输出一行,包含一个整数-1。
样例输入
3 1 0 2 1 0 2 3 4 0 3 1 0 2 4 3 4 0
样例输出
2 1 1 3 1 1 3 0 1
提示
按箭头方向的顺序分别为图 6 到图11 .
样例输入的游戏局面如上面第一个图片所示,依次移动的三步是: (2,1)处的方格向右移动, (3,1)处的方格向右移动, (3,0)处的方格向右移动,最后可以将棋盘上所有方块消除。
数据范围
对于 30%的数据,初始棋盘上的方块都在棋盘的最下面一行
对于 100%的数据,0 < n ≤5。
提示:时间限制为3s
不用说,这道题就是道枚举题。有枚举必有优化,由于优化的思路很明了,所以在这里先把可能的优化说完:
1.如果一个方块的左边也有方块,则不要向左移,因为左边的方块已经向右移过了。这个优化是最重要的优化,因为它能将解答树减去很大一截,加上它就足够过了。(时间有3s)
2.若某种颜色的方块存在但又不足3个,则无解。理论上这也是一个强力优化,但实际上只能帮你多过一两个点。
3.不要交换两个同色的方块。
关键是下落和消除的操作。消除稍微简单一点。理解题目后,发现可以这样实现消除:先横向扫描连续块,标记要消除的块,再纵向扫描连续块,标记要消除的块。若有标记,则说明有消除的操作:
bool destruct(int index, int r[X][Y]){ bool sign[X][Y]= {false}; bool bRet = false; for(int x=0; x<X; x++) { int count_ = 1; int color=r[x][0]; for(int y=1; y<Y; y++) { if(r[x][y] != color) { if(color && count_ >= 3) { for(int i = y-count_; i<y; i++) sign[x][i]=true; } color=r[x][y]; count_ = 1; } else if(!r[x][y]) { count_=0; color=0; } else { count_++; } } if(color && count_ >= 3) { for(int i = Y-count_; i<Y; i++) sign[x][i]=true; } } for(int y=0; y<Y; y++) { int count_ = 1; int color=r[0][y]; for(int x=1; x<X; x++) { if(r[x][y] != color) { if(color && count_ >= 3) { for(int i = x-count_; i<x; i++) sign[i][y]=true; } color=r[x][y]; count_ = 1; } else if(!r[x][y]) { count_=0; color=0; } else { count_++; } } if(color && count_ >= 3) { for(int i = X-count_; i<X; i++) sign[i][y]=true; } } for(int x=0; x<X; x++) { for(int y=0; y<Y; y++) { if(sign[x][y]) { bRet = true; count_[index][r[x][y]]--; //某种颜色的个数减一 r[x][y] = 0; } } } return bRet;}
真正重要的是下落操作。如果在原数据上交换过去交换过来的话,将会很麻烦。如果建立一个临时的数组重新建立一个游戏盘,再复制回原数组中的话就会很简单(就像输入数据一样):
void fall(int r[X][Y]){ int temp[X][Y] = {0}; for(int x=0; x<X; x++) { int cy = 0; for(int y=0; y<Y; y++) { if(r[x][y]) { temp[x][cy++] = r[x][y]; } } } memcpy(r,temp, sizeof(temp));}
最后注意优化一下常数时间。在比赛时能优化常数时间就必须要优化。
参考代码(仅供参考)
#include <cstdio>#include <cstdlib>#include <cmath>#include <cstring>#include <string>#include <iostream>#include <algorithm>#include <vector>#include <stack>#include <queue>#include <deque>#include <map>#include <set>using std::cin;using std::cout;using std::endl;inline int readIn(){ int a; scanf("%d",&a); return a;}const int X=5;const int Y=7;int n;bool isAns;int rect[7][X][Y];int ins[7][3];int count_[7][15];bool empty(int index){ for(int i=1; i<=10; i++) { if(count_[index][i]) return false; } return true;}void fall(int r[X][Y]){ int temp[X][Y] = {0}; for(int x=0; x<X; x++) { int cy = 0; for(int y=0; y<Y; y++) { if(r[x][y]) { temp[x][cy++] = r[x][y]; } } } memcpy(r,temp, sizeof(temp));}bool destruct(int index, int r[X][Y]){ bool sign[X][Y]= {false}; bool bRet = false; for(int x=0; x<X; x++) { int count_ = 1; int color=r[x][0]; for(int y=1; y<Y; y++) { if(r[x][y] != color) { if(color && count_ >= 3) { for(int i = y-count_; i<y; i++) sign[x][i]=true; } color=r[x][y]; count_ = 1; } else if(!r[x][y]) { count_=0; color=0; } else { count_++; } } if(color && count_ >= 3) { for(int i = Y-count_; i<Y; i++) sign[x][i]=true; } } for(int y=0; y<Y; y++) { int count_ = 1; int color=r[0][y]; for(int x=1; x<X; x++) { if(r[x][y] != color) { if(color && count_ >= 3) { for(int i = x-count_; i<x; i++) sign[i][y]=true; } color=r[x][y]; count_ = 1; } else if(!r[x][y]) { count_=0; color=0; } else { count_++; } } if(color && count_ >= 3) { for(int i = X-count_; i<X; i++) sign[i][y]=true; } } for(int x=0; x<X; x++) { for(int y=0; y<Y; y++) { if(sign[x][y]) { bRet = true; count_[index][r[x][y]]--; r[x][y] = 0; } } } return bRet;}void operate(int index, int x, int y, int g){ memcpy(rect[index+1],rect[index],sizeof(rect[index+1])); memcpy(count_[index+1],count_[index],sizeof(count_[index])); index++;#define r rect[index] std::swap(r[x][y], r[x+g][y]); fall(r); bool bOk = true; while(bOk) { bOk = false; bOk |= destruct(index, r); if(bOk) fall(r); }#undef r}void dfs(int index = 0){ if(index>n) return; if(empty(index)) { isAns = true; for(int i=0; i<index; i++) { printf("%d %d %d\n",ins[i][0],ins[i][1],ins[i][2]); } return; } else if(index==n) return; for(int x = 0; x<X; x++) { for(int y = 0; y<Y && rect[index][x][y]; y++) { for(int g=1; g>=-1; g-=2) { if(x+g<0 || x+g>=X) continue; if(g==-1 && rect[index][x+g][y]) continue; if(rect[index][x+g][y] == rect[index][x][y]) continue; ins[index][0]=x; ins[index][1]=y; ins[index][2]=g; operate(index,x,y,g); for(int i=1; i<=10; i++) { if(count_[index][i] && count_[index][i]<3) return; } dfs(index+1); if(isAns) return; } } }}void run(){ n=readIn(); for(int x=0; x<X; x++) { int y = 0; while(rect[0][x][y] = readIn()) { count_[0][rect[0][x][y]]++; y++; } } dfs(); if(!isAns) printf("-1\n");}int main(){ run(); return 0;}
- NOIP 2011 Senior 3
- NOIP 2011 Senior 2
- NOIP 2011 Senior 4
- NOIP 2011 Senior 5
- NOIP 2011 Senior 6
- NOIP 2009 Senior 3
- NOIP 2012 Senior 3
- NOIP 2015 Senior 3
- NOIP 2014 Senior 3
- NOIP 2013 Senior 3
- NOIP 2016 Senior 3
- NOIP 2003 Senior 3
- NOIP 2005 Senior 3
- NOIP 2017 Senior 3
- NOIP 2009 Senior 1
- NOIP 2009 Senior 4
- NOIP 2012 Senior 2
- NOIP 2012 Senior 5
- $.ajax()方法在请求成功后老是执行error中的函数
- lintcode 字符串查找(strStr) (Java)
- maven的settings.xml配置详解
- Android 事件总线EventBus
- 关于ListView加入HeaderView之后,点击条目时获得position参数移位的BUG修正
- NOIP 2011 Senior 3
- java实现人民币数字转换成中文
- caffe+windows+vs2015 (无GPU)环境配置
- TCP建立连接的三次握手过程
- UITextView中打开或禁用复制,剪切,选择,全选等功能
- 投影与三维视觉——本征矩阵和基础矩阵
- UIGeometry、UIDrawCall和UIWidget
- Tire树
- 推荐系统入门笔记