Noip2011 Mayan游戏 搜索 + 模拟 + 剪枝
写了一下午,终于AC了。
由于n<=5, 所以不需要太多的剪枝和技巧也能过。可以将操作后的消方块和下落和剪枝函数写到一个结构体中,这样会减少调试难度,更加简洁。
可以采用如下剪枝:
1. 如果当前有一种颜色少于两个,则一定无解。
2. 如果相邻颜色相同则不交换。
3. 优先考虑右移
4. 其实可以开一个unordered_map来避免重复搜索,由于笔者已经筋疲力尽,就没有进行这部优化(但其实n的规模太小,不开也无所谓)。
代码:
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<deque>
using namespace std;;
const int n = 7;
const int m = 5;
int board[10][10], spare[10][10], target;
struct Ans
{
int x,y,g;
Ans(int x = 0, int y = 0,int g = 0):x(x),y(y),g(g){}
};
deque<Ans>Q;
struct Operation
{
inline int get_num()
{
int cnt = 0;
for(int i = 1;i <= n; ++i)
for(int j = 1;j <= m; ++j)
if(spare[i][j])++cnt;
return cnt;
}
inline int cut()
{
int col[16];
memset(col,0,sizeof(col));
for(int i = 1;i <= n;++i)
for(int j = 1;j <= m;++j) ++ col[spare[i][j]];
for(int i = 1;i <= 15;++i)
if(col[i] && col[i] <= 2)return 1;
return 0;
}
inline int clear_block()
{
int flag = 0;
int mark[10][10];
memset(mark,0,sizeof(mark));
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= m;++j)
{
if(!spare[i][j])continue;
if(i + 2 <= n)
{
int cur = i;
while(spare[cur + 1][j] == spare[cur][j]) ++cur;
if(cur - i + 1 >= 3)
{
flag = 1;
int y = i;
while(spare[y][j] == spare[i][j]) mark[y][j] = 1, y += 1;
}
}
if(j + 2 <= m)
{
int cur = j;
while(spare[i][cur + 1] == spare[i][cur])++cur;
if(cur - j + 1 >= 3)
{
flag = 1;
int y = j;
while(spare[i][y] == spare[i][j]) mark[i][y] = 1, y += 1;
}
}
}
}
for(int i = 1;i <= n; ++i)
for(int j = 1;j <= m; ++j)
if(mark[i][j])spare[i][j] = 0;
return flag;
}
inline void down()
{
for(int col = 1; col <= m; ++col)
{
int bottom = n, cur = n;
while(bottom >= 1 && cur >= 1)
{
while(spare[bottom][col] && bottom >= 1) --bottom;
cur = bottom;
while(cur >= 1 && !spare[cur][col]) --cur;
if(cur >= 1)
{
int i = bottom ,j = cur;
while(spare[j][col] && j >= 1 && i >= 1)
{
spare[i][col] = spare[j][col];
spare[j][col] = 0;
--i;
--j;
}
}
}
}
}
inline void update()
{
down();
while(clear_block()) down();
}
}T;
void dfs(int nums,int arr[10][10])
{
for(int i = 1;i <= n;++i)
for(int j = 1;j <= m;++j)spare[i][j] = arr[i][j];
T.update();
for(int i = 1;i <= n;++i)
for(int j = 1;j <= m;++j)arr[i][j] = spare[i][j];
if(nums == target)
{
if(!T.get_num())
{
while(!Q.empty())
{
Ans p = Q.front();
printf("%d %d %d\n",p.x-1, 7-p.y, p.g);
Q.pop_front();
}
exit(0);
}
return;
}
if(!T.get_num() || T.cut())return;
int h[10][10];
memset(h,0,sizeof(h));
for(int i = 1;i <= n;++i)
for(int j = 1;j <= m;++j)h[i][j] = arr[i][j];
for(int j = 1;j <= m;++j)
for(int i = 7; i >= 1;--i)
{
if(!h[i][j])continue;
if(j < m && arr[i][j] != arr[i][j+1])
{
swap(h[i][j],h[i][j+1]);
Q.push_back(Ans(j,i,1));
dfs(nums+1,h);
Q.pop_back();
for(int i = 1;i <= n;++i)
for(int j = 1;j <= m;++j)h[i][j] = arr[i][j];
}
if(j > 1 && !arr[i][j-1])
{
swap(h[i][j],h[i][j-1]);
Q.push_back(Ans(j,i,-1));
dfs(nums+1,h);
Q.pop_back();
swap(h[i][j],h[i][j-1]);
for(int i = 1;i <= n;++i)
for(int j = 1;j <= m;++j)h[i][j] = arr[i][j];
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
scanf("%d",&target);
for(int i = 1;i <= 5; ++i)
{
for(int j = 7; ;--j)
{
int a;
scanf("%d",&a);
if(!a)break;
board[j][i] = a;
}
}
dfs(0,board);
printf("-1");
return 0;
}
Noip2011 Mayan游戏 搜索 + 模拟 + 剪枝的更多相关文章
- 洛谷 P1312 [ NOIP 2011 ] Mayan游戏 —— 搜索+模拟
题目:https://www.luogu.org/problemnew/show/P1312 还是不擅长这种题,所以参考了一下TJ: 其实也很好搜,按字典序,先搜右移,再搜左移: 不交换相同颜色的两个 ...
- Luogu P1312 Mayan游戏(搜索)
P1312 Mayan游戏 题意 题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个\(7\)行\(\times 5\)列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必 ...
- NOIP2011 Mayan游戏
3 Mayan游戏 题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上 ...
- [NOIP2011] mayan游戏(搜索+剪枝)
题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定 ...
- [noip2011 luogu1312] Mayan游戏(模拟)
原题:传送门 大模拟- 两个剪枝: 1.如果左边不为空就不往左边走(因为一定不如左边的移到右边优) 2.如果相邻两颜色相同不需移动 当然也有别的小剪枝(我没写)比如如果当前某一颜色剩余块数满足1< ...
- NOIP Mayan游戏 - 搜索
Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个7行5列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定的步数内消除所有 ...
- [NOIP2011]Mayan游戏 题解
题目大意: 有一个5*7的方格,上面有几种颜色的方块,如果在一横行或者竖列上有连续三个或者三个以上相同颜色的方块,则它们将立即被消除,方块消除之后,消除位置之上的方块将掉落.每步移动可以且仅可以沿横向 ...
- NOIp 2011 mayan游戏 搜索
题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定 ...
- noip2011 玛雅游戏 大模拟
深搜+模拟 需要剪枝:同一移动向右移了就不需要向左移了 #include<cstdio> #include<cstring> #include<iostream> ...
随机推荐
- 【ABCD组】Scrum meeting 4
前言 第4次会议在6月16日由组长在教9 405召开. 主要对下一步的工作进行说明安排,时长90min. 主要内容 分配下阶段任务,争取在这阶段完成软件的设计阶段 任务分配 姓名 当前阶段任务 贡献时 ...
- Docker学习总结(16)——当当网Docker应用实践
随着Docker成为当下热门的容器技术,各大公司以及中小团队都开始选择Docker来进行应用部署,从原有部署方式迁移到Docker方式过程中难免会遇到各种问题,本次分享主要介绍当当网个性化推荐组应用D ...
- 洛谷 P2010 回文日期
Noip2016普及组T2 题目描述 在日常生活中,通过年.月.日这三个要素可以表示出一个唯一确定的日期. 牛牛习惯用8位数字表示一个日期,其中,前4位代表年份,接下来2位代表月 份,最后2位代表日期 ...
- rmq问题和lca可以相互转化
Sparse Table算法 一般RMQ的Sparse Table(ST)算法是基于倍增思想设计的O(Nlog2N) – O(1)在线算法 算法记录从每个元素开始的连续的长度为2k的区间中元素的最小值 ...
- Java 学习(8):java 方法
Java方法是语句的集合,它们在一起执行一个功能. 方法是解决一类问题的步骤的有序组合 方法包含于类或对象中 方法在程序中被创建,在其他地方被引用 命名规则: 1. 必须以 字母.'_'或'$'开头. ...
- 0816关于MySQL的审计 init-connect+binlog实现用户操作追踪
转自:http://blog.sina.com.cn/s/blog_605f5b4f01013xkv.html mysql 用init-connect+binlog实现用户操作追踪 做access 的 ...
- iostat -x 1 查看磁盘的IO负载
Linux系统出现了性能问题.一般我们能够通过top.iostat,vmstat等命令来查看初步定位问题.当中iostat能够给我们提供丰富的IO状态数据 $ iostat -x -1 avg-cp ...
- 《从零開始学Swift》学习笔记(Day48)——类型检查与转换
原创文章,欢迎转载.转载请注明:关东升的博客 继承会发生在子类和父类之间,是一系列类的继承关系. 比如:Person是类层次结构中的根类.Student是Person的直接子类.Worker是Pers ...
- Task.ConfigureAwait
public ConfiguredTaskAwaitable ConfigureAwait( bool continueOnCapturedContext ) Configures an awaite ...
- poj1700--贪心--Crossing River
Crossing River Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 12260 Accepted: 4641 D ...