NOIP2011 Mayan游戏(搜索)

第一反应是搜索题,想了一下如果用BFS的话,由于状态过多,可能超内存,因此我用的DFS。

这里我们讨论一下剪枝条件:

如果当前状态有一种颜色的数量小于3,那么这种颜色就无法被消除,因此我们可以提前退出迭代。

如果两个连着的方块颜色是相同的话,我们不用交换。

如果两个非空的方块交换,我们只用考虑左边那个方块右移,而不用考虑右边方块左移的情况,这样就能做到右移优先。

如果一个方块是空的,它的右边非空,我们就只用考虑它右边的方块左移,当枚举到它右边方块的时候也不需要再考虑左移的情况。

注意下落清除方块的时候要写成循环形式,因为清除方块以后,下落形成的新图形可能又出现了能清除的方块。

下面是我第一次写的下落的程序,有一个BUG,如果上方多个方块连在一起,而最下面方块的下面是空的,根据我的最先写的程序,只有最下面的一个方块会往下掉,因此我们要一列一列的枚举,把目标状态先求出来

void drop()
{
	for(int x = 0; x < 5; x++)
		for(int y = 6; y >= 1; y--)
			if(st[x][y] != 0&&st[x][y-1] == 0)
				swap(st[x][y],st[x][y-1]);
   	return;
}
void drop()//改进后的代码
{
	int num[10][10];
    memset(num,-1,sizeof num);
    for(int x = 0; x < 5; x++)//这一步是按照合法的情况重新排版
    {
        int h=0;
        for(int y = 0; y < 7; y++)
        	if(st[x][y])
            	num[x][h++] = y;
    }
    for(int x = 0; x < 5; x++)
        for(int y = 0; y < 7; y++)
    		st[x][y] = num[x][y] == -1?0:st[x][num[x][y]];
   	return;
}

到了这里,这道题的思路就很简单了,就是写的时候有点坑爹

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
using namespace std;
struct T
{
	int x,y,ops;
}ans[10];
int st[10][10];
int n;
bool empty()//判断是否全部消除完
{
	for(int i = 0; i < 5; i++)
		for(int j = 0; j < 7; j++)
			if(st[i][j]) return false;
	return true;
}
void drop()//下移
{
	int num[10][10];
    memset(num,-1,sizeof num);
    for(int x = 0; x < 5; x++)//这一步是按照合法的情况重新排版
    {
        int h=0;
        for(int y = 0; y < 7; y++)
        	if(st[x][y])
            	num[x][h++] = y;
    }
    for(int x = 0; x < 5; x++)
        for(int y = 0; y < 7; y++)
    		st[x][y] = num[x][y] == -1?0:st[x][num[x][y]];
   	return;
}
bool clear()//清除合法的联通块,本题的难点
{
	bool flag = 0;
	for(int x = 0; x < 3; x++)//横向判断,因为至少3个相同的连在一起,因此x只用枚举到2
		for(int y = 0; y < 7; y++)
		if(st[x][y])//有方块
		{
			int x2;
			for(x2 = x; x2+1<5&&st[x2+1][y] == st[x][y]; x2++);
			if(x2 - x >= 2)//至少有3个连在一起
			{
				int tx;
				for(tx = x; tx <= x2; tx++)//竖向判断是否有共用的情况
				{
					int Up = y,Dn = y;
					while(Up+1<7&&st[tx][Up+1] == st[x][y]) Up++;
					while(Dn-1>=0&&st[tx][Dn-1] == st[x][y]) Dn--;
					if(Up - Dn >= 2)
					{
						int ty;
						for(ty = Dn; ty <= Up; ty++)
							st[tx][ty] = 0;
					}
				}
				for(tx = x; tx <= x2; tx++)
					st[tx][y] = 0;
				flag = 1;
			}
		}
	for(int x = 0; x < 5; x++)
		for(int y = 0; y < 5; y++)
		if(st[x][y])
		{
			int y2;
			for(y2 = y; y2+1<7&&st[x][y2+1] == st[x][y]; y2++);
			if(y2 - y >= 2)
			{
				int ty;
				for(ty = y; ty <= y2; ty++)
				{
					int Lf = x,Ri = x;
					while(Lf-1>=0&&st[Lf-1][ty] == st[x][y]) Lf--;
					while(Ri+1<7&&st[Ri+1][ty] == st[x][y]) Ri++;
					if(Ri - Lf >= 2)
					{
						int tx;
						for(tx = Lf; tx <= Ri; tx++)
							st[tx][ty] = 0;
					}
				}
				for(ty = y; ty <= y2; ty++)
					st[x][ty] = 0;
				flag = 1;
			}
		}
	if(flag) return true;
	else return false;
}
void dfs(int step)
{
	if(step > n)
	{
		if(empty())
		{
			for(int i = 1; i <= n; i++)
			{
				if(ans[i].ops)//ops等于1是代表x右边那块往左移
					printf("%d %d %d\n",ans[i].x+1,ans[i].y,-1);
				else
					printf("%d %d %d\n",ans[i].x,ans[i].y,1);
			}
			exit(0);
		}
		return;
	}

	int sum[12];
	memset(sum,0,sizeof sum);
	for(int x = 0; x < 5; x++)//如果一个数它的个数已经小于3了,则不能被消除
		for(int y = 0; y < 7; y++)
			sum[st[x][y]]++;
	for(int i = 1; i <= 10; i++)
		if(sum[i] != 0&&sum[i] < 3) return;

	for(int x = 0; x < 4; x++)
		for(int y = 0; y < 7; y++)
		if(st[x][y] != st[x+1][y])//颜色相同的就不用交换了
		{
			ans[step].x = x;
			ans[step].y = y;
			ans[step].ops = (!st[x][y]);//如果当前这一块是空的话,那么我们就把它右边那一块左移,避免了分情况讨论
			int temp[10][10];
			memcpy(temp,st,sizeof temp);
			swap(st[x][y],st[x+1][y]);

			drop();
			while(clear()) drop();//下移之后还肯能产生新的合法联通块,因此写成循环的形式

			dfs(step+1);//迭代加深

			ans[step].x = 0;
			ans[step].y = 0;
			ans[step].ops = 0;
			memcpy(st,temp,sizeof st);
		}
}
int main()
{
	scanf("%d",&n);
	for(int i = 0; i < 5; i++)
	{
		for(int j = 0; ; j++)
		{
			scanf("%d",&st[i][j]);
			if(st[i][j] == 0) break;
		}
	}
	dfs(1);
	printf("-1\n");
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-07 04:32:24

NOIP2011 Mayan游戏(搜索)的相关文章

NOIP2011tg mayan游戏(搜索)

题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定的步数内消除所有的方块,消除方块的规则如下: 1 .每步移动可以且仅可以沿横向(即向左或向右)拖动某一方块一格:当拖动这一方块时,如果拖动后到达的位置(以下称目标位置)也有方块,那么这两个方块将交换位置(参见输入输出样例说明中的图6 到图7 ):如果目标位置上没有方块,那么被拖动的方块将从原来的竖列

NOIp2011 mayan游戏

传送门 题目描述 Mayan puzzle 是最近流行起来的一个游戏.游戏界面是一个 7行 5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定的步数内消除所有的方块,消除方块的规则如下: 1.  每步移动可以且仅可以沿横向(即向左或向右)拖动某一方块一格:当拖动这一方块时,如果拖动后到达的位置(以下称目标位置)也有方块,那么这两个方块将交 换位置(参见输入输出样例说明中的图 6 到图 7):如果目标位置上没有方块,那么被拖动的方

NOIP2011 Mayan游戏 题解

描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个7行5列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定的步数内消除所有的方块,消除方块的规则如下: 1.每步移动可以且仅可以沿横向(即向左或向右)拖动某一方块一格:当拖动这一方块时,如果拖动后到达的位置(以下称目标位置)也有方块,那么这两个方块将交换位置(参见图6到图7):如果目标位置上没有方块,那么被拖动的方块将从原来的竖列中抽出,并从目标位置上掉落(直到不悬

NOIp 2011 mayan游戏 搜索

搜索. 因为要求字典序最小 所以都右移 除非那个方格为空. 代码如下: 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #define For(i,x,y) for(int i=x;i<=y;++i) 6 using namespace std; 7 int a[10][10]; 8 int cnt[10];int n; int ncnt

【noip2011】【codevs1136】Mayan游戏

3.Mayan 游戏(mayan.cpp/c/pas)[问题描述]Mayan puzzle 是最近流行起来的一个游戏.游戏界面是一个7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定的步数内消除所有的方块,消除方块的规则如下:1.每步移动可以且仅可以沿横向(即向左或向右)拖动某一方块一格:当拖动这一方块时,如果拖动后到达的位置(以下称目标位置)也有方块,那么这两个方块将交换位置(参见输入输出样例说明中的图6 到图7):如果

P1312 Mayan游戏 [模拟][搜索]

P1312 Mayan游戏 这道题跟斗地主都是大模拟啊!稍微挂一点可能就爆零了! 图肯定能存,直接二维数组扔进去即可. 然后套dfs模板,搜索就先照那样搜. 核心操作有两个:一个是判断那些块可以消掉,一个是把那些可以消的消了. 第一个操作的核心代码是这样的: for(int i = 1; i <= 5; i++) { for(int j = 1; j <= 7; j++) { if(G[i][j] && i - 1 >= 1 && i + 1 <=

洛谷 P1312 Mayan游戏

P1312 Mayan游戏 题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定的步数内消除所有的方块,消除方块的规则如下: 1 .每步移动可以且仅可以沿横向(即向左或向右)拖动某一方块一格:当拖动这一方块时,如果拖动后到达的位置(以下称目标位置)也有方块,那么这两个方块将交换位置(参见输入输出样例说明中的图6 到图7 ):如果目标位置上没有方块,那

洛谷P1312 [NOIOP2011提高组 Day1T3]Mayan游戏

Mayan游戏 题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定的步数内消除所有的方块,消除方块的规则如下: 1 .每步移动可以且仅可以沿横向(即向左或向右)拖动某一方块一格:当拖动这一方块时,如果拖动后到达的位置(以下称目标位置)也有方块,那么这两个方块将 交换位置(参见输入输出样例说明中的图6 到图7 ):如果目标位置上没有方块,那么被拖动的

noip提高组2011 Mayan游戏

Mayan游戏 描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个7行5列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.**游戏通关是指在规定的步数内消除所有的方块,**消除方块的规则如下: 1.每步移动可以且仅可以沿横向(即向左或向右)拖动某一方块一格:当拖动这一方块时,如果拖动后到达的位置(以下称目标位置)也有方块,那么这两个方块将交换位置(参见图6到图7):如果目标位置上没有方块,那么被拖动的方块将从原来的竖列中抽出,并从