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> ...
随机推荐
- .net 单元测试
都说测试驱动开发,但是想写好单元测试其实不容易,不是因为测试用例难以构造,而是因为很多时候方法非常复杂 其中部分测试想要完成就十分费力,其中让人崩溃的地方主要如下: 实例私有函数 实例静态私有函数 十 ...
- 使用Layer完成图片放大功能
序言:在写这个功能之前也用了zoom.js,zoom.js用起来简单引用js然后设置图片属性就可以放大.但是放大后的图片模糊.没有遮罩.在放大图片时其它图片布局会受到影响,当然如果觉得这些都是小问题的 ...
- WEB测试范围小结
根据<用户需求说明手册>和<需求分析说明书>,分析各个功能模块.针对各个功能模块进行相关功能的测试. 链接测试 链接是Web 网站的一个主要特征,它是在页面之间切换和引导用户去 ...
- LightOJ - 1231 - Coin Change (I)
先上题目: 1231 - Coin Change (I) PDF (English) Statistics Forum Time Limit: 1 second(s) Memory Limit: ...
- [bzoj2049][Sdoi2008]Cave 洞穴勘测_LCT
Cave 洞穴勘测 bzoj-2049 Sdoi-2008 题目大意:维护一个数据结构,支持森林中加边,删边,求两点连通性.n个点,m个操作. 注释:$1\le n\le 10^4$,$1\le m\ ...
- tcpip学习
http://www.cnblogs.com/ggjucheng/archive/2012/08/18/2645324.html
- POJ 1625
什么鬼,真的是有负数的吗?我在字符加上了128才过了.dp[i][j],经过i步到达j状态的路径数.转移很容易了,建个trie图就可以,由前一步可连通到和更新即可. 另外,要用到大数和AC自动机DP ...
- Poj 1321 棋盘问题 【回溯、类N皇后】
id=1321" target="_blank">棋盘问题 Time Limit: 1000MS Memory Limit: 10000K Total Subm ...
- OLR文件丢失的恢复
11.2.0.1的RAC中,rac1和rac2 一.OLR有备份的情况 1.手动将rac1中的olr重命名,模拟丢失 mv rac1.olr rac1.olr.test 2.重新启动crs ./crs ...
- Oracle学习(十二):存储过程/存储函数
1.知识点 --第一个存储过程 /* 打印Hello World create [or replace] PROCEDURE 过程名(參数列表) AS PLSQL子程序体: 调用存储过程: 1. ex ...