NOIP2011【Mayan游戏】



【题解】

   一题比较玄学的搜索,虽然我一直不明白为什么不会T但正解就是这个

   首先很容易想到用右移(1)代替左移(-1)保证字典序(若当前这格是空格才是左移)

   每次搜索一步就做清理(clear)注意一定要多次清理直到无法清理为止,由于矩阵比较小(5*7)所以掉落了清理的步骤就随便做一下(参考程序中clear)(打这个的时候把变量打错了调了一个小时,汗)

   最后走了走了n步后判断有没有全被清完就好了

   一个小优化,每次搜索前,判断有没有一种颜色数量小于三,有的话跳出

  详见代码

  

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cstdio>
#include <queue>
#include <ctime>
#include <cmath>
using namespace std;
int i,j,k,m,n;
int a[10][10],num[10],c[10][10];
struct info
  {
  	int x,y,d;
  }ans[10];
bool empty()
  {
  	for (int i=0;i<5;i++) if (a[i][0]!=0) return 0;
	return 1; 
  }
bool clear()
  {
  	int i,j,k,l,pd=0,x,y,o;
  	memset(c,0,sizeof c);
  	for (i=0;i<5;i++)
  	  for (j=l=0;j<7;j++) if (a[i][j]) c[i][l++]=a[i][j];
  	if (ans[1].x==2&&ans[2].x==1&&ans[3].x==2&&ans[1].y==0&&ans[2].y==1&&ans[3].y==4&&ans[1].d==0&&ans[2].d==0&&ans[3].d==1)
	    {
	      k=0;
		 } 
  	for (i=0;i<3;i++)
  	  for (j=0;j<7;j++)
  	    if (c[i][j])
		  {
  	    	for (x=i+1;x<5&&c[x][j]==c[i][j];x++);x--;
  	    	if (x-i+1>=3) 
  	    	  {
				for (k=i;k<=x;k++)
				  {
				  	for (l=j;l>=0&&c[k][l]==c[k][j];)
					    l--;
					  l++;
				  	for (y=j;y<7 &&c[k][y]==c[k][j];)
					  y++;
					  y--;
				  	if (y-l+1>=3) for (o=l;o<=y;o++) c[k][o]=0;
				  	else c[k][j]=0;
				  }
				pd=1;
			  }
		  }
    for (i=0;i<5;i++)
  	  for (j=0;j<5;j++)
  	    if (c[i][j])
		  {
  	    	for (y=j+1;y<7&&c[i][y]==c[i][j];y++);y--;
  	    	if (y-j+1>=3) 
  	    	  {
				for (o=j;o<=y;o++)
				  {
				  	for (l=i;l>=0&&c[l][o]==c[i][o];l--);l++;
				  	for (x=i;x<5 &&c[x][o]==c[i][o];x++);x--;
				  	if (x-l+1>=3) for (k=l;k<=x;k++) c[k][o]=0;
				  	else c[i][o]=0;
				  }
				pd=1;
			  }
		  }
	memcpy(a,c,sizeof a);
	return pd;
  }
void dfs(int k)
  {
  	int i,j;
  	if (k>n)
  	  {
  	  	if (empty())
  	  	  {
  	  	  	for (int i=1;i<=n;i++)
  	  	  	  if (ans[i].d) printf("%d %d -1\n",ans[i].x+1,ans[i].y);
  	  	  	  else printf("%d %d 1\n",ans[i].x,ans[i].y);
  	  	  	exit(0);
		  }
	    return;
	  }
	
	memset(num,0,sizeof(num));
	for (i=0;i<5;i++) for (j=0;j<7;j++) num[a[i][j]]++;
	for (i=1;i<=10;i++) if (num[i]<=2&&num[i]>=1) return;
		
    for (i=0;i<4;i++)
      for (j=0;j<7;j++)
        if (a[i+1][j]!=a[i][j])
		  {
		  	int b[10][10];
		  	memcpy(b,a,sizeof(b));
        	ans[k]=(info){i,j,!a[i][j]};
        	swap(a[i+1][j],a[i][j]);
        	for (;clear(););
        	dfs(k+1);
        	memcpy(a,b,sizeof(a));
		  }
  }
int main()
  {
  	scanf("%d",&n);
  	for (i=0;i<5;i++)
	   for (j=0;;j++) 
		  {
		    scanf("%d",&a[i][j]);
		    if (!a[i][j]) break;
		  }
	dfs(1);
	printf("-1");	  
  }

  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值