Description
Mayan puzzle
是最近流行起来的一个游戏。游戏界面是一个(7)行×(5)列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上。游戏通关是指在规定的步数内消除所有的方块,消除方块的规则如下:
1 、每步移动可以且仅可以沿横向(即向左或向右)拖动某一方块一格:当拖动这一方块时,如果拖动后到达的位置(以下称目标位置)也有方块,那么这两个方块将交换位置(参见输入输出样例说明中的图(6)到图(7));如果目标位置上没有方块,那么被拖动的方块将从原来的竖列中抽出,并从目标位置上掉落(直到不悬空,参见下面图(1)和图(2));
2 、任一时刻,如果在一横行或者竖列上有连续三个或者三个以上相同颜色的方块,则它们将立即被消除(参见图(1)到图(3))。
注意:
-
如果同时有多组方块满足消除条件,几组方块会同时被消除(例如下面图(4),三个颜色为(1)的方块和三个颜色为(2)的方块会同时被消除,最后剩下一个颜色为(2)的方块)。
-
当出现行和列都满足消除条件且行列共享某个方块时,行和列上满足消除条件的所有方块会被同时消除(例如下面图(5)所示的情形,(5)个方块会同时被消除)。
-
方块消除之后,消除位置之上的方块将掉落,掉落后可能会引起新的方块消除。注意:掉落的过程中将不会有方块的消除。
上面图(1)到图(3)给出了在棋盘上移动一块方块之后棋盘的变化。棋盘的左下角方块的坐标为((0),(0)),将位于((3),(3))的方块向左移动之后,游戏界面从图(1)变成图(2)所示的状态,此时在一竖列上有连续三块颜色为(4)的方块,满足消除条件,消除连续(3)块颜色为(4)的方块后,上方的颜色为(3)的方块掉落,形成图(3)所示的局面。
Input
共(6)行。
第一行为一个正整数(n),表示要求游戏通关的步数。
接下来的(5)行,描述(7)×(5)的游戏界面。每行若干个整数,每两个整数之间用一个空格隔开,每行以一个(0)结束,自下向上表示每竖列方块的颜色编号(颜色不多于(10)种,从(1)开始顺序编号,相同数字表示相同颜色)。
输入数据保证初始棋盘中没有可以消除的方块。
Output
如果有解决方案,输出(n)行,每行包含(3)个整数(x),(y),(g),表示一次移动,每两个整数之间用一个空格隔开,其中((x,y))表示要移动的方块的坐标,(g)表示移动的方向,(1)表示向右移动,(−1)表示向左移动。注意:多组解时,按照(x)为第一关健字,(y)为第二关健字,(1)优先于(-1) ,给出一组字典序最小的解。游戏界面左下角的坐标为((0,0))。
如果没有解决方案,输出一行,包含一个整数(−1)。
Sample Input
3
1 0
2 1 0
2 3 4 0
3 1 0
2 4 3 4 0
Sample Output
2 1 1
3 1 1
3 0 1
Hint
按箭头方向的顺序分别为图(6)到图(11)
样例输入的游戏局面如上面第一个图片所示,依次移动的三步是:((2,1))处的方格向右移动,((3,1))处的方格向右移动,((3,0))处的方格向右移动,最后可以将棋盘上所有方块消除。
对于(30%)的数据,初始棋盘上的方块都在棋盘的最下面一行;
对于(100%)的数据,(0<n≤5)。
(noip2011)提高组(day1)第(3)题
题解
无脑码农题,改错改了半天。最后不得不在(Luogu)下了如下数据才该对……
数据
数据一:
Input
2
1 0
1 0
0
1 0
1 0
Output
-1
数据二:
Input
5
1 1 2 3 4 0
3 3 1 2 3 5 4 0
3 5 5 3 2 2 0
5 5 3 5 2 4 2 0
0
Output
0 4 1
0 2 1
1 3 1
3 2 1
3 0 1
定义:
-
(mp[][])记录读入的图,(Step)记录需要的步数
-
(Res[][])记录每一步的状态,(Ans[][])记录最终答案
-
(flag)标记是否找到答案,(YH[])数组用于优化
const int maxn=15,maxstep=10,maxh=10,maxl=10;
int Step,mp[maxh][maxl],Res[maxstep][4];
int Ans[maxstep][4],flag,YH[maxn];
读入
读入很简单,但是第二层循环不要打成
for(int j=1;j<=7;++j)
因为有些输入输入了(8)个数,最后一项为(0)
void Read()
{
scanf("%d",&Step);
int num;
for(int i=1;i<=5;++i)
for(int j=1;;++j)
{
scanf("%d",&num);
if(num) mp[i][j]=num;
else break;
}
}
下落
这个很简单,自己动手模拟一下就可以了:
void Change(int (*nw)[maxl])
{
int cnt;
for(int i=1;i<=5;++i)
{
cnt=0;
for(int j=1;j<=7;++j)
if(nw[i][j])
{
if(cnt) nw[i][j-cnt]=nw[i][j],nw[i][j]=0;
}
else ++cnt;
}
}
清理
这个坑点很多,比如如果有四个、五个、……个连续的颜色是一起消除,还有图(5)所示的情况……
我用的是用一个数组记录原来的数组,再行与列分开清理。
bool Clean(int (*nw)[maxl])
{
int tmp[maxh][maxl];
for(int i=1;i<=5;++i)
for(int j=1;j<=7;++j) tmp[i][j]=nw[i][j];
int cnt; bool flag=0;
for(int i=1;i<=5;++i)
{
cnt=0;
for(int j=1;j<=7;++j)
{
if(tmp[i][j])
{
if(tmp[i][j]==tmp[i][j-1]) ++cnt;
else cnt=1;
}
else cnt=0;
if(cnt==3)
{
flag=1,
nw[i][j-2]=nw[i][j-1]=nw[i][j]=0;
}
else if(cnt>3) nw[i][j]=0;
}
}
for(int j=1;j<=7;++j)
{
cnt=0;
for(int i=1;i<=5;++i)
{
if(tmp[i][j])
{
if(tmp[i][j]==tmp[i-1][j]) ++cnt;
else cnt=1;
}
else cnt=0;
if(cnt==3)
{
flag=1,
nw[i-2][j]=nw[i-1][j]=nw[i][j]=0;
}
else if(cnt>3) nw[i][j]=0;
}
}
return flag;
}
深搜
深搜部分码量大,我们一个一个看,首先我们看一个减枝:
bool Cut(int (*nw)[maxl])
{
for(int i=0;i<maxn;++i) YH[i]=0;
for(int i=1;i<=5;++i)
for(int j=1;j<=7;++j) ++YH[nw[i][j]];
for(int i=1;i<maxn;++i)
if((YH[i])&&(YH[i]<3)) return 1;
return 0;
}
因为如果一种方块小于(3)个的话,那么它绝对不会被消那么继续(DFS)下去肯定找不到解,当存在这种情况时,我们就返回真。
下面这个函数返回的是它的移动情况,返回值的意义如下:
-
若为(0),则该数既不能左移,也不能右移
-
若为(1),则该数只能左移
-
若为(2),则该数只能右移
-
若为(3),则该数既能左移,也能右移
设该数所处的位置为((x,y))所有的情况如下:
-
若(x)为(1),则它不能左移;若(x)为(5),则它不能右移
-
仅仅只有((x-1,y))的位置没数时,该数才能左移;因为若((x-1,y))的位置有数,则((x-1,y))的右移就等价于((x,y))的左移,但是前者的字典序更小
-
若((x+1,y))的位置有数时,该数不需要右移
int Let_me_think_think(int x,int y,int nw[maxh][maxl])
{
if(!nw[x][y]) return 0;
if(x==1)
{
if(nw[x][y]!=nw[x+1][y]) return 1;
return 0;
}
if(x==5)
{
if(nw[x-1][y]) return 0;
return 2;
}
if(nw[x-1][y])
{
if(nw[x][y]!=nw[x+1][y]) return 1;
return 0;
}
if(nw[x][y]!=nw[x+1][y]) return 3;
return 2;
}
下面是一个简单的交换函数,不必解释
void Swap(int &a,int &b)
{
int tmp;
tmp=a,a=b,b=tmp;
}
最后就是很简单很麻烦的(DFS)了
void Dfs(int res,int nw[maxh][maxl])
{
if(flag) return;
if(res>Step)
{
Check(nw); return;
}
if(Cut(nw)) return;
int tmp[maxh][maxl],QAQ;
for(int i=1;i<=5;++i)
for(int j=1;j<=7;++j)
{
QAQ=Let_me_think_think(i,j,nw);
if(!QAQ) continue;
if(QAQ==1||QAQ==3)
{
for(int ii=1;ii<=5;++ii)
for(int jj=1;jj<=7;++jj) tmp[ii][jj]=nw[ii][jj];
Res[res][1]=i,Res[res][2]=j,Res[res][3]=1;
Swap(tmp[i][j],tmp[i+1][j]);
Change(tmp);
while(Clean(tmp)) Change(tmp);
Dfs(res+1,tmp);
}
if(QAQ==2||QAQ==3)
{
for(int ii=1;ii<=5;++ii)
for(int jj=1;jj<=7;++jj) tmp[ii][jj]=nw[ii][jj];
Res[res][1]=i,Res[res][2]=j,Res[res][3]=-1;
Swap(tmp[i][j],tmp[i-1][j]);
Change(tmp);
while(Clean(tmp)) Change(tmp);
Dfs(res+1,tmp);
}
}
}
整体代码:
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=15,maxstep=10,maxh=10,maxl=10;
int Step,mp[maxh][maxl],Res[maxstep][4];
int Ans[maxstep][4],flag,YH[maxn];
void Read()
{
scanf("%d",&Step);
int num;
for(int i=1;i<=5;++i)
for(int j=1;;++j)
{
scanf("%d",&num);
if(num) mp[i][j]=num;
else break;
}
}
void Check(int nw[maxh][maxl])
{
for(int i=1;i<=5;++i)
for(int j=1;j<=7;++j)
if(nw[i][j]) return;
for(int i=1;i<=Step;++i)
Ans[i][1]=Res[i][1],
Ans[i][2]=Res[i][2],
Ans[i][3]=Res[i][3];
flag=1;
}
int Let_me_think_think(int x,int y,int nw[maxh][maxl])
{
if(!nw[x][y]) return 0;
if(x==1)
{
if(nw[x][y]!=nw[x+1][y]) return 1;
return 0;
}
if(x==5)
{
if(nw[x-1][y]) return 0;
return 2;
}
if(nw[x-1][y])
{
if(nw[x][y]!=nw[x+1][y]) return 1;
return 0;
}
if(nw[x][y]!=nw[x+1][y]) return 3;
return 2;
}
void Swap(int &a,int &b)
{
int tmp;
tmp=a,a=b,b=tmp;
}
void Change(int (*nw)[maxl])
{
int cnt;
for(int i=1;i<=5;++i)
{
cnt=0;
for(int j=1;j<=7;++j)
if(nw[i][j])
{
if(cnt) nw[i][j-cnt]=nw[i][j],nw[i][j]=0;
}
else ++cnt;
}
}
bool Clean(int (*nw)[maxl])
{
int tmp[maxh][maxl];
for(int i=1;i<=5;++i)
for(int j=1;j<=7;++j) tmp[i][j]=nw[i][j];
int cnt; bool flag=0;
for(int i=1;i<=5;++i)
{
cnt=0;
for(int j=1;j<=7;++j)
{
if(tmp[i][j])
{
if(tmp[i][j]==tmp[i][j-1]) ++cnt;
else cnt=1;
}
else cnt=0;
if(cnt==3)
{
flag=1,
nw[i][j-2]=nw[i][j-1]=nw[i][j]=0;
}
else if(cnt>3) nw[i][j]=0;
}
}
for(int j=1;j<=7;++j)
{
cnt=0;
for(int i=1;i<=5;++i)
{
if(tmp[i][j])
{
if(tmp[i][j]==tmp[i-1][j]) ++cnt;
else cnt=1;
}
else cnt=0;
if(cnt==3)
{
flag=1,
nw[i-2][j]=nw[i-1][j]=nw[i][j]=0;
}
else if(cnt>3) nw[i][j]=0;
}
}
return flag;
}
bool Cut(int (*nw)[maxl])
{
for(int i=0;i<maxn;++i) YH[i]=0;
for(int i=1;i<=5;++i)
for(int j=1;j<=7;++j) ++YH[nw[i][j]];
for(int i=1;i<maxn;++i)
if((YH[i])&&(YH[i]<3)) return 1;
return 0;
}
void Dfs(int res,int nw[maxh][maxl])
{
if(flag) return;
if(res>Step)
{
Check(nw); return;
}
if(Cut(nw)) return;
int tmp[maxh][maxl],QAQ;
for(int i=1;i<=5;++i)
for(int j=1;j<=7;++j)
{
QAQ=Let_me_think_think(i,j,nw);
if(!QAQ) continue;
if(QAQ==1||QAQ==3)
{
for(int ii=1;ii<=5;++ii)
for(int jj=1;jj<=7;++jj) tmp[ii][jj]=nw[ii][jj];
Res[res][1]=i,Res[res][2]=j,Res[res][3]=1;
Swap(tmp[i][j],tmp[i+1][j]);
Change(tmp);
while(Clean(tmp)) Change(tmp);
Dfs(res+1,tmp);
}
if(QAQ==2||QAQ==3)
{
for(int ii=1;ii<=5;++ii)
for(int jj=1;jj<=7;++jj) tmp[ii][jj]=nw[ii][jj];
Res[res][1]=i,Res[res][2]=j,Res[res][3]=-1;
Swap(tmp[i][j],tmp[i-1][j]);
Change(tmp);
while(Clean(tmp)) Change(tmp);
Dfs(res+1,tmp);
}
}
}
void Print()
{
if(!flag) {puts("-1");return;}
for(int i=1;i<=Step;++i)
printf("%d %d %d
",Ans[i][1]-1,Ans[i][2]-1,Ans[i][3]);
}
int main()
{
Read();
Change(mp);
while(Clean(mp)) Change(mp);
Dfs(1,mp);
Print();
return 0;
}