写了一下午,终于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游戏 搜索 + 模拟 + 剪枝的更多相关文章

  1. 洛谷 P1312 [ NOIP 2011 ] Mayan游戏 —— 搜索+模拟

    题目:https://www.luogu.org/problemnew/show/P1312 还是不擅长这种题,所以参考了一下TJ: 其实也很好搜,按字典序,先搜右移,再搜左移: 不交换相同颜色的两个 ...

  2. Luogu P1312 Mayan游戏(搜索)

    P1312 Mayan游戏 题意 题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个\(7\)行\(\times 5\)列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必 ...

  3. NOIP2011 Mayan游戏

    3 Mayan游戏 题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上 ...

  4. [NOIP2011] mayan游戏(搜索+剪枝)

    题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定 ...

  5. [noip2011 luogu1312] Mayan游戏(模拟)

    原题:传送门 大模拟- 两个剪枝: 1.如果左边不为空就不往左边走(因为一定不如左边的移到右边优) 2.如果相邻两颜色相同不需移动 当然也有别的小剪枝(我没写)比如如果当前某一颜色剩余块数满足1< ...

  6. NOIP Mayan游戏 - 搜索

    Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个7行5列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定的步数内消除所有 ...

  7. [NOIP2011]Mayan游戏 题解

    题目大意: 有一个5*7的方格,上面有几种颜色的方块,如果在一横行或者竖列上有连续三个或者三个以上相同颜色的方块,则它们将立即被消除,方块消除之后,消除位置之上的方块将掉落.每步移动可以且仅可以沿横向 ...

  8. NOIp 2011 mayan游戏 搜索

    题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定 ...

  9. noip2011 玛雅游戏 大模拟

    深搜+模拟 需要剪枝:同一移动向右移了就不需要向左移了 #include<cstdio> #include<cstring> #include<iostream> ...

随机推荐

  1. 如鹏网JAVA培训笔记2(晓伟整理)

    输入输出: 我们使用System.out.println(“abc”);作用:向控制台输入东西. Scaner sc=new Scanner(System.in)://从输入流中去读取 int age ...

  2. html绑定点击事件传值

    1.方法1function radioSelect(event){ var valueRadio=event.value; if(valueRadio =='目的口岸'){ return '目的口岸' ...

  3. 基于Mysql-Proxy 实现MariaDB 读写分离

    一.Mysql-Proxy 简单介绍 MySQL-Proxy是一个处于你的client端和MySQL server端之间的简单程序,它可以监测.分析或改变它们的通信.它使用灵活,没有限制,常见的用途包 ...

  4. ACDream - k-GCD

    先上题目: B - k-GCD Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others) Sub ...

  5. error at ::0 can't find referenced pointcut...解决方法

    error at ::0 can't find referenced pointcut...解决方法 学习了:http://dyldragon.iteye.com/blog/512612 升级aspe ...

  6. Linux USB 驱动开发(一)—— USB设备基础概念【转】

    本文转载自:http://blog.csdn.net/zqixiao_09/article/details/50984074 在终端用户看来,USB设备为主机提供了多种多样的附加功能,如文件传输,声音 ...

  7. Linux - 虚拟机中的三种网络连接,桥接、NAT、Host-only详解

    虚拟机中的三种网络连接 1.桥接 2.NAT 3.Host-only 桥接方便做实验,配置ip方便.可以和局域网中的其他机器进行通信,也可以和公网进行通信.缺点是会占用一个ip. NAT,可以和主机进 ...

  8. net快速写入/读取大量数据Postgresql

    Postgresql快速写入/读取大量数据 http://www.cnblogs.com/podolski/p/7152144.html 环境及测试 使用.net驱动npgsql连接post数据库.配 ...

  9. php获取uniqid

    md5(uniqid(microtime(true),true))

  10. JS函数种类详解

    1. 普通函数1.1 示例 1 2 3 function ShowName(name) {   alert(name); } 1.2 Js中同名函数的覆盖 在Js中函数是没有重载,定义相同函数名.不同 ...