题目大意

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

1 、每步移动可以且仅可以沿横向(即向左或向右)拖动某一方块一格:当拖动这一方块时,如果拖动后到达的位置(以下称目标位置)也有方块,那么这两个方块将交换位置(参见输入输出样例说明中的图66到图77 );如果目标位置上没有方块,那么被拖动的方块将从原来的竖列中抽出,并从目标位置上掉落(直到不悬空,参见下面图1 和图2);

2 、任一时刻,如果在一横行或者竖列上有连续三个或者三个以上相同颜色的方块,则它们将立即被消除(参见图1 到图3)。

注意:

a) 如果同时有多组方块满足消除条件,几组方块会同时被消除(例如下面图44 ,三个颜色为11 的方块和三个颜色为 22 的方块会同时被消除,最后剩下一个颜色为22的方块)。

b) 当出现行和列都满足消除条件且行列共享某个方块时,行和列上满足消除条件的所有方块会被同时消除(例如下面图5 所示的情形,5 个方块会同时被消除)。

3 、方块消除之后,消除位置之上的方块将掉落,掉落后可能会引起新的方块消除。注意:掉落的过程中将不会有方块的消除。

上面图1 到图 3 给出了在棋盘上移动一块方块之后棋盘的变化。棋盘的左下角方块的坐标为(0, 0 ),将位于(3, 3 )的方块向左移动之后,游戏界面从图 1 变成图 2 所示的状态,此时在一竖列上有连续三块颜色为4 的方块,满足消除条件,消除连续3 块颜色为4 的方块后,上方的颜色为3 的方块掉落,形成图 3 所示的局面。

若有解,输出具体移动方案,否则输出-1.

题解

如何模拟消除过程

  1. 每当我们消除掉一组块后,剩余的块新的排列方式我们是不可预估的。所以,我们应当不断对全局进行可消除的块的搜索并消除,而不是删除哪个块就在哪个块附近尝试考虑各种情况来删除。
  2. 对于一组块如何删除?一定不要忘记图5的情况!另外,在时间复杂度够的情况下,我们要尽可能使用简单粗暴的形式解决问题。与其边删块边让上面的块下落,不如删的时候只删不下落,最后设置个DropAll函数把所有块整体下落,这样一定不会错。

如何剪枝

  1. 优化搜索顺序:根据题目中的优先级,我们可以按从左到右、从下至上进行搜索。
  2. 排除等效冗余:我们不允许两个颜色相同的块交换;所有块不可以与左侧相邻的块交换。
  3. 可行性剪枝:本题看不出什么规律来,无法在此处剪枝。
  4. 最优性剪枝:本题没要你求最优解,无法在此处剪枝。
  5. 记忆化:本题状态存储不了,无法在此处剪枝。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>
using namespace std; const int MAX_ROW = 10, MAX_COL = 10;
const int TotX = 5, TotY = 7;
int N; struct Matrix
{
int A[MAX_ROW][MAX_COL]; private:
int GetHorSum(int x, int y)
{
int color = A[x][y];
int ans = 1;
for (int i = x - 1; i >= 0 && A[i][y] == color; i--)
ans++;
for (int i = x + 1; i < TotX && A[i][y] == color; i++)
ans++;
return ans;
} int GetVerSum(int x, int y)
{
int color = A[x][y];
int ans = 1;
for (int i = y + 1; i < TotY && A[x][i] == color; i++)
ans++;
for (int i = y - 1; i >= 0 && A[x][i] == color; i--)
ans++;
return ans;
} void DropOne(int x, int y)
{
if (A[x][y])
for (int i = y - 1; i >= 0 && !A[x][i]; i--)
swap(A[x][i], A[x][i + 1]);
} void DropAll()
{
for (int x = 0; x < TotX; x++)
for (int y = 0; y < TotY; y++)
DropOne(x, y);
} void RemoveHor(int, int);
void RemoveVer(int, int); bool Remove(int x, int y)
{
if (GetHorSum(x, y) >= 3)
{
RemoveHor(x, y);
DropAll();
return true;
}
if (GetVerSum(x, y) >= 3)
{
RemoveVer(x, y);
DropAll();
return true;
}
return false;
} bool Search_Remove()
{
for (int x = 0; x < TotX; x++)
for (int y = 0; y < TotY && A[x][y]; y++)
if (Remove(x, y))
return true;
return false;
} void RemoveAll()
{
while (Search_Remove());
} public:
Matrix operator = (const Matrix& a)
{
memcpy(A, a.A, sizeof(a.A));
return *this;
} bool operator == (const Matrix& a) const
{
return !memcmp(A, a.A, sizeof(A));
} bool Empty()
{
for (int x = 0; x < TotX; x++)
if (A[x][0])
return false;
return true;
} Matrix Move(int x, int y, int dir)
{
Matrix ans;
ans = *this;
assert(ans.A[x][y]);
assert(x + dir < TotX && x + dir >= 0);
if (ans.A[x + dir][y])
swap(ans.A[x][y], ans.A[x + dir][y]);
else
{
swap(ans.A[x][y], ans.A[x + dir][y]);
ans.DropAll();
}
ans.RemoveAll();
return ans;
}
}; void Matrix::RemoveHor(int x, int y)
{
int color = A[x][y];
A[x][y] = 0;
for (int i = x - 1; i >= 0 && A[i][y] == color; i--)
{
if (GetVerSum(i, y) >= 3)
RemoveVer(i, y);
A[i][y] = 0;
}
for (int i = x + 1; i < TotX && A[i][y] == color; i++)
{
if (GetVerSum(i, y) >= 3)
RemoveVer(i, y);
A[i][y] = 0;
}
} void Matrix::RemoveVer(int x, int y)
{
int color = A[x][y];
A[x][y] = 0;
for (int i = y - 1; y >= 0 && A[x][i] == color; i--)
{
if (GetHorSum(x, i) >= 3)
RemoveHor(x, i);
A[x][i] = 0;
}
for (int i = y + 1; y < TotY && A[x][i] == color; i++)
{
if (GetHorSum(x, i) >= 3)
RemoveHor(x, i);
A[x][i] = 0;
}
} struct State
{
Matrix mat;
int X, Y, Dir;
}States[10]; bool Ok(int cnt)
{
for (int i = 0; i < cnt; i++)
if (States[i].mat == States[cnt].mat)
return false;
return true;
} int Dfs(int cnt)
{
if (cnt > N)
return -1;
for (int x = 0; x < TotX; x++)
for (int y = 0; y < TotY && States[cnt - 1].mat.A[x][y]; y++)
{
States[cnt].X = x;
States[cnt].Y = y;
const Matrix& matFrom = States[cnt - 1].mat;
if (x <= TotX - 2 && matFrom.A[x + 1][y] != matFrom.A[x][y])
{
States[cnt].Dir = 1;
States[cnt].mat = States[cnt - 1].mat.Move(x, y, 1);
if (States[cnt].mat.Empty())
return cnt;
if (Ok(cnt))
{
int nextAns = Dfs(cnt + 1);
if (nextAns > -1)
return nextAns;
}
}
if (x >= 1 && !matFrom.A[x - 1][y])
{
States[cnt].Dir = -1;
States[cnt].mat = States[cnt - 1].mat.Move(x, y, -1);
if (States[cnt].mat.Empty())
return cnt;
if (Ok(cnt))
{
int nextAns = Dfs(cnt + 1);
if (nextAns > -1)
return nextAns;
}
}
}
return -1;
} int main()
{
scanf("%d", &N);
for (int x = 0; x < TotX; x++)
for (int y = 0; scanf("%d", &States[0].mat.A[x][y]) && States[0].mat.A[x][y]; y++); int cnt = Dfs(1);
if (cnt == -1)
printf("-1\n");
else
{
for (int i = 1; i <= cnt; i++)
printf("%d %d %d\n", States[i].X, States[i].Y, States[i].Dir);
}
return 0;
}

  

luogu1312 Mayan游戏 剪枝的更多相关文章

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

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

  2. NOIP2011 Mayan游戏

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

  3. noip提高组2011 Mayan游戏

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

  4. $Mayan$游戏

    \(Mayan\)游戏 好啊,一年(半年)来的梦魇,终于结束了. 其实我从来没料到整体竟然会如此暴力--做的时候机房里冷得很,感觉晕晕乎乎地做完了,晕晕乎乎地调了好久,晕晕乎乎地听(看了题解的)\(q ...

  5. [Luogu 1312] noip11 Mayan游戏

    [Luogu 1312] noip11 Mayan游戏 Problem: Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即 ...

  6. Luogu P1312 Mayan游戏(搜索)

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

  7. 洛谷P1312 [NOIP2011提高组Day1T3]Mayan游戏

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

  8. [题目] Luogu P1312 Mayan游戏

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

  9. 洛谷P1312 Mayan游戏

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

随机推荐

  1. C# 窗体 切换、重复显示等遗留问题解决(第五天)

    一.解决同一窗体多次点击重复显示BUG (1)点击弹出学校窗体 #region 弹出学校窗体 /// <summary> /// 弹出学校窗体 /// </summary> / ...

  2. strut2 拦截器 使用

    拦截器是strut2里一个很振奋人心的应用.通过配置拦截器可以在action执行之前进行一些初始化或者是其他的操作,但是在action执行之后,返回结果就已经确定,结果是很难改变了(目前我还不知道怎么 ...

  3. @ResponseBody 返回中文乱码

    第一种解决方法:在@RequestMapping注解添加produces属性 @RequestMapping(value = "testPersonalValidtor.do",p ...

  4. 微服务的一种开源实现方式——dubbo+zookeeper

    转自: http://blog.csdn.NET/zhdd99/article/details/52263609 微服务架构成了当下的技术热点,实现微服务是要付出很大成本的,但也许是因为微服务的优点太 ...

  5. Android控件的继承关系

    1.View,ViewGroup >View: }1.所有高级UI组件都继承View类而实现的 }2.一个View在屏幕上占据一块矩形区域 }3. 负责渲染 }4.负责处理发生的事件 }5.设置 ...

  6. /etc目录常用配置文件

    /etc/resolv.conf DNS客户端配置文件,逐渐被网卡配置文件所替代 /etc/hosts 本机DNS解析文件,优先级高于DNS服务器 /etc/hostname CentOS 7 主机名 ...

  7. UGUI世界坐标转换为UI本地坐标(游戏Hud的实现)

    实现世界坐标的原理是: 世界坐标和UGUI的坐标分属两个坐标系,他们之间是无法进行转换的,需要通过屏幕坐标系来进行转换(因为屏幕坐标是固定的),即先将游戏场景中的世界坐标通过游戏场景Camera转化为 ...

  8. js可以随意拖拽的div的实现

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. HDU-1864&&HDU-2602(01背包问题)

    DP-01背包问题例题 输入处理有点恶心人,不过处理完后就是简单的DP了 从头开始dp[i]表示从0开始到i的最优结果,最后从都边里dp数组,求得最大的报销额. 对于每个i都要从头维护最优结果.(二刷 ...

  10. java的四舍五入及取整

    四舍五入用 Math.round(double a): 向上取整用 Math.ceil(double a): 向下取整用 Math.floor(double a):