测试地址:Mayan游戏

做法:这一道题目很长,看起来也很复杂,其实只要处理好这些操作的过程,再加一些简单的剪枝就可以AC了。

题目要求字典序最小的解,因此就按照题目中的字典序DFS,再实时记录当前棋盘的状态即可。根据题目中所给的最优解的性质,可以得到一个剪枝方案:对于有方块的位置,如果它在左边界,则将它向右移,继续搜索。如果它在中间,那么先将它向右移,搜索,然后判断,如果它的左边为空,则将它向左移并搜索,如果不为空,就不用继续搜索了,因为这一种情况一定在前面搜到它左边这个方块的时候就已经搜过了。如果它在右边界,则判断左边是否为空,如果为空就将它向左移,继续搜索。这个剪枝就足以节省大约一半的时间了。实际上,要是处理得好的话,只加这个剪枝就可以AC了。

以下是本人代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n;
struct {int x,y,g;} step[10]; //记录每一步的信息
struct matrix {int s[10][10];} M; //记录棋盘状态

bool isempty(matrix a) //判断当前棋盘是否已被清空
{
  for(int x=0;x<5;x++)
    for(int y=0;y<7;y++)
	  if (a.s[x][y]!=0) return 0;
  return 1;
}

void fall(matrix &a) //处理因重力而下落的情况
{
  int top[6]={0};
  for(int j=1;j<7;j++)
    for(int i=0;i<5;i++)
	{
	  if (!a.s[i][top[i]]) swap(a.s[i][j],a.s[i][top[i]]);
	  if (a.s[i][top[i]]) top[i]++;
	}
}

bool breaker(matrix &a) //搜索有没有能被消除的方块,有则消除并返回true,否则返回false
{
  bool br[10][10]={0},flag=0; //br数组存储当前方块是否能被消除
  int r,rc;
  for(int i=0;i<5;i++)
  {
    r=rc=0;
    for(int j=0;j<7;j++)
	{
	  if (rc!=a.s[i][j]||a.s[i][j]==0)
	  {
	    r=1;
		rc=a.s[i][j];
	  }
	  else
	  {
	    r++;
		if (r>3) {br[i][j]=1;flag=1;}
		if (r==3) {br[i][j]=br[i][j-1]=br[i][j-2]=1;flag=1;} //注意不是直接消除,而是标记,想一想为什么?
	  }
	}
  }
  for(int j=0;j<7;j++)
  {
    r=rc=0;
    for(int i=0;i<5;i++)
	{
	  if (rc!=a.s[i][j]||a.s[i][j]==0)
	  {
	    r=1;
		rc=a.s[i][j];
	  }
	  else
	  {
	    r++;
		if (r>3) {br[i][j]=1;flag=1;}
		if (r==3) {br[i][j]=br[i-1][j]=br[i-2][j]=1;flag=1;}
	  }
	}
  }
  for(int i=0;i<5;i++)
    for(int j=0;j<7;j++)
	  if (br[i][j]) a.s[i][j]=0;
  return flag;
}

matrix change(matrix a,int x,int y,int g)
{
  matrix c;
  c=a;
  swap(c.s[x][y],c.s[x+g][y]);
  fall(c);
  while(breaker(c)) fall(c);
  return c;
}

bool dfs(int f,matrix last) //DFS,当前已走f步,状态为last
{
  if (isempty(last))
  {
    if (f==n) return 1;
	else return 0;
  }
  else if (f==n) return 0;
  for(int x=0;x<5;x++)
    for(int y=0;y<7;y++)
	  if (last.s[x][y]!=0)
	  {
	    step[f+1].x=x;step[f+1].y=y;
		if (x<4&&last.s[x][y]!=last.s[x+1][y])
		{
		  step[f+1].g=1;
		  if (dfs(f+1,change(last,x,y,1))) return 1;
		  if (x>0&&last.s[x-1][y]==0)
		  {
		    step[f+1].g=-1;
			if (dfs(f+1,change(last,x,y,-1))) return 1;
		  }
		}
		if (x==4&&last.s[x-1][y]==0)
		{
		  step[f+1].g=-1;
		  if (dfs(f+1,change(last,x,y,-1))) return 1;
	    }
	  }
  return 0;
}

int main()
{
  scanf("%d",&n);
  memset(M.s,0,sizeof(M.s));
  for(int i=0;i<5;i++)
  {
    int j=0,a;
    while(scanf("%d",&a)&&a!=0) M.s[i][j++]=a; 
  }
  
  if (n==0) {printf("-1");return 0;}
  if (!dfs(0,M)) printf("-1");
  else
  {
    for(int i=1;i<=n;i++)
	  printf("%d %d %d\n",step[i].x,step[i].y,step[i].g);
  }
  
  return 0;
}