[NOIP2011]Mayan游戏 题解

时间:2022-06-23 17:41:52

题目大意:

  有一个5*7的方格,上面有几种颜色的方块,如果在一横行或者竖列上有连续三个或者三个以上相同颜色的方块,则它们将立即被消除,方块消除之后,消除位置之上的方块将掉落。每步移动可以且仅可以沿横向拖动某一方块一格:当拖动这一方块时,如果拖动后到达的目标位置也有方块,那么这两个方块将交换位置;如果目标位置上没有方块,那么被拖动的方块将从原来的竖列中抽出,并从目标位置上掉落,直到不悬空。输入一个正整数n ,表示要求游戏通关的步数,输出方案(多组解时,按照 x 为第一关健字,y 为第二关健字,1优先于-1 ,给出一组字典序最小的解)

思路:

  因为n小于等于5,因此按字典序搜索方案,移动后按要求模拟(全零的要注意),减枝为若要移动的方块左侧不为空则该方案不是最优,可以舍去。

代码:(太丑陋了)

 #include<cstdio>
#include<cstring>
using namespace std;
#define copy(x,y) memcpy(x,y,sizeof(x))
#define sousuo x[k]=i,y[k]=j,dfs(k+1),tot=t,copy(map,a),copy(hight,b)
int map[][],hight[],x[],y[],z[],ansx[],ansy[],ansz[],i,n,tot,k;
bool flag; void wk(int x,int y,int z)
{
int i,c[][];
if (map[z][y]) i=map[x][y],map[x][y]=map[z][y],map[z][y]=i;
else
{
map[z][hight[z]++]=map[x][y];
for (;y<hight[x];y++) map[x][y]=map[x][y+];
map[x][hight[x]--]=;
}
for (bool f=;f;)
{
f=;
memset(c,,sizeof(c));
for (i=;i<;i++)
for (x=y=;y<=hight[i];)
if (map[i][x]==map[i][y]) y++;
else
{
if (y-x>) for (f=;x<y;x++) c[i][x]=;
x=y;
}
for (i=;i<;i++)
for (x=y=;y<;)
if (map[x][i]==map[y][i]) y++;
else
{
if (y-x> && map[x][i]) for (f=;x<y;x++) c[x][i]=;
x=y;
}
for (i=;i<;i++)
{
for (x=y=;y<hight[i];)
{
while (c[i][y]) y++,tot--;
if (y==hight[i]) break;
map[i][x++]=map[i][y++];
}
for (y=x;y<;y++) map[i][y]=;
hight[i]=x;
}
}
} void dfs(int k)
{
if (flag) return;
if (k>n)
{
if (!tot) flag=,copy(ansx,x),copy(ansy,y),copy(ansz,z);
return;
}
if (!tot) return;
int a[][],b[],t=tot;
copy(a,map),copy(b,hight);
for (int i=;i<;i++)
for (int j=;j<b[i];j++)
{
if (i<) wk(i,j,i+),z[k]=,sousuo;
if (i && !a[i-][j]) wk(i,j,i-),z[k]=-,sousuo;//jianzhi
}
} int main()
{
scanf("%d",&n);
for (i=;i<;i++)
for (scanf("%d",&k);k;scanf("%d",&k)) map[i][hight[i]++]=k;
for (i=;i<;i++) tot+=hight[i]; dfs();
if (flag) for (i=;i<=n;i++) printf("%d %d %d\n",ansx[i],ansy[i],ansz[i]);
else printf("-1");
return ;
}