Luogu 1312 【NOIP2011】玛雅游戏 (搜索)
Luogu 1312 【NOIP2011】玛雅游戏 (搜索)
Description
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 所示的局面。
Input
共6 行。
第一行为一个正整数n,表示要求游戏通关的步数。
接下来的5 行,描述7 * 5 的游戏界面。每行若干个整数,每两个整数之间用一个空格隔开,每行以一个0 结束,自下向上表示每竖列方块的颜色编号(颜色不多于10 种,从1 开始顺序编号,相同数字表示相同颜色)。
输入数据保证初始棋盘中没有可以消除的方块。
Output
如果有解决方案,输出n 行,每行包含3 个整数x,y,g,表示一次移动,每两个整数之间用一个空格隔开,其中(x,y)表示要移动的方块的坐标,g 表示移动的方向,1 表示向右移动,-1 表示向左移动。注意:多组解时,按照x 为第一关健字,y 为第二关健字,1优先于-1,给出一组字典序最小的解。游戏界面左下角的坐标为(0,0)。
如果没有解决方案,输出一行,包含一个整数-1。
Sample Input
3
1 0
2 1 0
2 3 4 0
3 1 0
2 4 3 4 0
Sample Output
2 1 1
3 1 1
3 0 1
Http
Luogu:https://www.luogu.org/problem/show?pid=1312
Source
搜索
解决思路
首先观察题目的数据范围,给出了棋盘面积固定是5*7,并且给出了固定的步数,所以我们可以想到搜索的方法。
搜索搜什么?每一步我们我们搜索一个要移动的格子,然后再看它是向左还是向右移动,移动完后再进行消除和下滑操作。
说起来不难,但是细节和剪枝需要注意。
细节:
1.题目输入的方式需要处理,为了方便操作,这里采用左下角为(1,1)的方式编号。
2.注意输出的格式是先纵行再横列,并且从0开始编号,即这里程序中的(i,j)输出时要变成(j-1,i-1)
3.处理下落时要从最底下开始,即从行1开始
4.消除是可以连续的,即如果两个消除有重叠的部分,也都是要消除的。不能找到一个就立刻在矩阵中修改,比如有4个连在一起的,如果扫到第2个时就把前三个直接消除了,那么第4个就不会被消除。所以要单独标记出来,全部扫描后再统一消除
几个剪枝
1.因为题目给出了字典序的定义,所以我们以列j为外循环行i为内循环,先向右移再向左移的搜索顺序来进行,这样保证找到的第一个可行解的字典序最小。
2.对于向左移的情况,如果左边的格子不是空的,则不需要这一步,因为如果这两个格子都有,那么交换这两个格子的状态已经在前面搜索过了
3.在一个状态中如果存在一种颜色数量为1或2,则直接退出,因为这时不可能存在解。
4.如果两个方块的颜色是一样的,则没有必要交换,因为没有意义
个人亲测,第2,4条剪枝是最有用的,而第1条是必加的。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxN=9;
const int N=7;
const int M=5;
const int inf=2147483647;
int Step;
int Mat[maxN][maxN];//棋盘
int Outp[15][5];//存下输出时需要的信息
void dfs(int step);//搜索移动哪一个
void Clear();//清除相连的和向下掉落
void OutpMat();//中间输出查看
int main()
{
memset(Mat,0,sizeof(Mat));
scanf("%d",&Step);
for (int i=1;i<=5;i++)//读入,并将其处理成需要的格式
{
int j=1;
int x;
while ((scanf("%d",&x)!=EOF)&&(x!=0))
{
Mat[j][i]=x;
j++;
}
}
//OutpMat();
dfs(1);
cout<<-1<<endl;//无解输出-1
return 0;
}
void dfs(int step)//搜索,step表示是第几步
{
if (step==Step+1)//当达到目标时,检查是否清除完毕
{
Clear();//保险起见,再进行一次清除和掉落
for (int i=1;i<=7;i++)
for (int j=1;j<=5;j++)
if (Mat[i][j]!=0)//检测是否全部为0
return;
for (int i=1;i<=Step;i++)
printf("%d %d %d\n",Outp[i][1]-1,Outp[i][2]-1,Outp[i][3]);//注意-1,因为题目从0开始编号
exit(0);//结束程序
}
int nowMat[maxN][maxN];//备份当前矩阵
int Colorcnt[11];//剪枝3,统计每一种颜色的个数
memset(Colorcnt,0,sizeof(Colorcnt));
for (int i=1;i<=7;i++)
for (int j=1;j<=5;j++)
Colorcnt[Mat[i][j]]++;
for (int i=1;i<=10;i++)
if ((Colorcnt[i]==1)||(Colorcnt[i]==2))//统计个数不满足时,直接退出
return;
memcpy(nowMat,Mat,sizeof(Mat));//备份原矩阵
for (int j=1;j<=5;j++)
for (int i=1;i<=7;i++)
if (nowMat[i][j]!=0)//只有当前格子存在方块才进行操作
{
if ((j!=5)&&(nowMat[i][j]!=nowMat[i][j+1]))//剪枝4,颜色相同时不交换
{
memcpy(Mat,nowMat,sizeof(Mat));//将矩阵置为当前这一步
swap(Mat[i][j],Mat[i][j+1]);//交换
Clear();//处理下落和消除
Outp[step][1]=j;//记录信息
Outp[step][2]=i;
Outp[step][3]=1;
dfs(step+1);
}
if ((j!=1)&&(nowMat[i][j-1]==0)&&(nowMat[i][j]!=nowMat[i][j-1]))//剪枝3和4,当左边的不为空时不进行操作
{
memcpy(Mat,nowMat,sizeof(Mat));
swap(Mat[i][j],Mat[i][j-1]);
Clear();
Outp[step][1]=j;
Outp[step][2]=i;
Outp[step][3]=-1;
dfs(step+1);
}
}
return;
}
void Clear()//处理下落和清除
{
bool cls[maxN][maxN];//cls代表当前消除的方块
while (1)
{
for (int i=2;i<=7;i++)//将可以下落的方块下落
for (int j=1;j<=5;j++)
if ((Mat[i][j]!=0)&&(Mat[i-1][j]==0))
{
int k=i;
while ((k>=2)&&(Mat[k][j]!=0)&&(Mat[k-1][j]==0))
{
Mat[k-1][j]=Mat[k][j];
Mat[k][j]=0;
k--;
}
}
memset(cls,0,sizeof(cls));//寻找能够清除的方块
bool is_cls=0;//标记这一轮中是否有清除操作,如果没有说明清除完毕
for (int i=1;i<=7;i++)
for (int j=1;j<=5;j++)
{
if ((Mat[i][j]!=0)&&(Mat[i][j]==Mat[i][j-1])&&(Mat[i][j]==Mat[i][j+1]))//横向三连
{
is_cls=1;
cls[i][j]=cls[i][j-1]=cls[i][j+1]=1;
}
if ((Mat[i][j]!=0)&&(Mat[i][j]==Mat[i+1][j])&&(Mat[i][j]==Mat[i-1][j]))//纵向三连
{
is_cls=1;
cls[i][j]=cls[i+1][j]=cls[i-1][j]=1;
}
}
if (is_cls==0)
break;
for (int i=1;i<=7;i++)
for (int j=1;j<=5;j++)
if (cls[i][j]==1)//将清除的置为空
Mat[i][j]=0;
}
return;
}
void OutpMat()
{
for (int i=1;i<=7;i++)
{
for (int j=1;j<=5;j++)
cout<<Mat[i][j]<<" ";
cout<<endl;
}
cout<<endl;
return;
}
Luogu 1312 【NOIP2011】玛雅游戏 (搜索)的更多相关文章
- NOIP2011玛雅游戏
闲的没事干,出来写一下早两天刷的一道搜索题NOIP2011玛雅游戏,其实这道题还是比较水的,虽然看起来可能有点复杂. 方法很简单粗暴,直接根据规则模拟就行. 话不多说直接上代码(关键操作在注释中有提到 ...
- [NOIP2011]玛雅游戏
闲的没事干,出来写一下早两天刷的一道搜索题NOIP2011玛雅游戏,其实这道题还是比较水的,虽然看起来可能有点复杂. 方法很简单粗暴,直接根据规则模拟就行. 话不多说直接上代码(关键操作在注释中有提到 ...
- [Luogu 1312] noip11 Mayan游戏
[Luogu 1312] noip11 Mayan游戏 Problem: Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即 ...
- Noip2011 Mayan游戏 搜索 + 模拟 + 剪枝
写了一下午,终于AC了. 由于n<=5, 所以不需要太多的剪枝和技巧也能过.可以将操作后的消方块和下落和剪枝函数写到一个结构体中,这样会减少调试难度,更加简洁. 可以采用如下剪枝: 1. 如果当 ...
- noip2011 玛雅游戏 大模拟
深搜+模拟 需要剪枝:同一移动向右移了就不需要向左移了 #include<cstdio> #include<cstring> #include<iostream> ...
- [COGS 622] [NOIP2011] 玛雅游戏 模拟
整个模拟的关键除了打出来就是一个剪枝:对于两个左右相邻的块你不用再走←,因为走→是等效的 #include<cstdio> #include<cstring> #include ...
- [NOIP2011] mayan游戏(搜索+剪枝)
题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定 ...
- 玛雅游戏[NOIP2011]
题目描述 Mayan puzzle 是最近流行起来的一个游戏.游戏界面是一个7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定 ...
- [Luogu 1640] SCOI2010 连续攻击游戏
[Luogu 1640] SCOI2010 连续攻击游戏 DP太恶心,回来二分图这边放松一下心智. 这个建图真的是难以想到. 因为要递增啊,属性值放x部,装备放y部,对应连边跑Hungary就好了. ...
随机推荐
- Final 个人最终作业。
1.对软件工程M1/M2做一个总结 在M1阶段,我在C705组.M1阶段我与黄漠源同学结对,一起完成提取关键词算法的优化.最初我们一起测试提取关键词算法功能的实现效果,随后我主要负责从网络上搜寻并整理 ...
- 北航学堂Android客户端Beta阶段发布说明
在从学姐那里拿到服务接口的代码最终连通服务器之后,经过我们团队的努力,终于把前后端融合生成了我们目前的版本, 因为我们在Alpha阶段网络连接部分是一直没有搞定的,所以这个版本其实并不算是真正的Bet ...
- 个人博客作业-Week1
1.五个问题 1) 团队编程中会不会因为人们意见的分歧而耽误时间,最终导致效率降低? 2)软件团队中测试的角色应该独立出来吗 3)对于团队编程,如果没有时间测试他人的新功能,因此就不添加该新功能,那会 ...
- BugPhobia发布篇章:Beta版本学霸在线系统正式发布
0x00:测试报告版本管理 版本号 具体细节 修订时间 V 1.0 整理第一轮迭代用户管理和登陆注册的功能性验证测试,预计将继续网页对浏览器版本的兼容性测试 2015/11/12 V1.0.1 整理第 ...
- Daily Scrumming* 2015.12.22(Day 14)
一.团队scrum meeting照片 二.成员工作总结 姓名 任务ID 迁入记录 江昊 任务1112 无 任务说明 今天没有写前端界面,而是完成了跨域请求的实现以及用户实名认证API 前后端大部分数 ...
- 第八周--Linux中进程调度与进程切换的过程
[潘恒 原创作品转载请注明出处 <Linux内核分析>MOOC课程 "http://mooc.study.163.com/course/USTC 1000029000 " ...
- R和python语言如何求平均值,中位数和众数
均值是通过取数值的总和并除以数据序列中的值的数量来计算. R语言平均值公式: mean(x, trim = 0, na.rm = FALSE, ...)#x - 是输入向量.trim - 用于从排序的 ...
- Oracle的简单的创建dblink以及进行数据迁移的方法
1. 创建dblink 语法如下: create public database link zhaobsh connect to lcoe739999 identified by Test6530 u ...
- linux_压缩解压命令(zip/tar)
一.zip 1.压缩 格式 $ zip (选项) (文件/目录) 选项 -r 参数表示递归打包包含子目录的全部内容. -q 参数表示为安静模式,即不向屏幕输出信息. -o 表示输出文件,需在其后紧跟打 ...
- css CSS常见布局解决方案
CSS常见布局解决方案说起css布局,那么一定得聊聊盒模型,清除浮动,position,display什么的,但本篇本不是讲这些基础知识的,而是给出各种布局的解决方案.水平居中布局首先我们来看看水平居 ...