NOIP2011 Mayan游戏 题解

描述

Mayan puzzle是最近流行起来的一个游戏。游戏界面是一个7行5列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上。游戏通关是指在规定的步数内消除所有的方块,消除方块的规则如下:

1、每步移动可以且仅可以沿横向(即向左或向右)拖动某一方块一格:当拖动这一方块时,如果拖动后到达的位置(以下称目标位置)也有方块,那么这两个方块将交换位置(参见图6到图7);如果目标位置上没有方块,那么被拖动的方块将从原来的竖列中抽出,并从目标位置上掉落(直到不悬空,参见图1和图2);

2、任一时刻,如果在一横行或者竖列上有连续三个或者三个以上相同颜色的方块,则它们将立即被消除(参见图1到图3)。

注意:

a) 如果同时有多组方块满足消除条件,几组方块会同时被消除(例如下面图4,三个颜色为1的方块和三个颜色为2的方块会同时被消除,最后剩下一个颜色为2的方块)。

b) 当出现行和列都满足消除条件且行列共享某个方块时,行和列上满足消除条件的所有方块会被同时消除(例如下面图5所示的情形,5个方块会同时被消除)。

3、方块消除之后,消除位置之上的方块将掉落,掉落后可能会引起新的方块消除。注意:掉落的过程中将不会有方块的消除。

上面图1到图3给出了在棋盘上移动一块方块之后棋盘的变化。棋盘的左下角方块的坐标为(0, 0),将位于(3, 3)的方块向左移动之后,游戏界面从图1变成图2所示的状态,此时在一竖列上有连续三块颜色为4的方块,满足消除条件,消除连续3块颜色为4的方块后,上方的颜色为3的方块掉落,形成图3所示的局面。

格式

输入格式

第一行为一个正整数n,表示要求游戏关的步数。

接下来的5行,描述7*5的游戏界面。每行若干个整数,每两个整数之间用一个空格隔开,每行以一个0 结束,自下向上表示每竖列方块的颜色编号(颜色不多于10种,从1开始顺序编号,相同数字表示相同颜色)。

输入数据保证初始棋盘中没有可以消除的方块。

输出格式

如果有解决方案,输出n行,每行包含3个整数x,y,g,表示一次移动,每两个整数之间用一个空格隔开,其中(x,y)表示要移动的方块的坐标,g表示移动的方向,1表示向右移动,-1表示向左移动。注意:多组解时,按照x为第一关键字,y为第二关键字,1优先于-1,给出一组字典序最小的解。游戏界面左下角的坐标为(0, 0)。

如果没有解决方案,输出一行,包含一个整数-1。

样例1

样例输入1[复制]

3
1 0
2 1 0
2 3 4 0
3 1 0
2 4 3 4 0

样例输出1[复制]

2 1 1
3 1 1
3 0 1

限制

3s

提示

样例输入的游戏局面如图6到图11所示。依次移动的三步是:(2,1)处的方格向右移动,(3,1)处的方格向右移动,(3,0)处的方格向右移动,最后可以将棋盘上所有方块消除。

数据规模如下:

对于30%的数据,初始棋盘上的方块都在棋盘的最下面一行;

对于100%的数据,0 < n ≤ 5。

在做题时应注意:

(1)不用枚举整个棋盘,只需要每列都搜索到最高层即可。

(2)我们发现把(x,y)向右移和把(x+1,y)向左移是一样的,不用重复搜索,所以我们可以只向右交换,此外还应注意到空格不能移动,所以要判断这种特殊情况。

(3)应注意到可能出现以下状况:

即出现十字型。

(4)为了提高效率,防止一个点被算不止一次,所以要等到全部搜索完再统一消去。

(5)注意左右移动时要先判断是否下落。

先来一个30分的做法 :

program mayan;

type

armap=array[0..7,0..5] of longint;

tnode=record

end;

var

n:longint;//步数

map:armap;

procedure init;

begin

assign(input,‘mayan.in‘);

assign(output,‘mayan.out‘);

reset(input);

rewrite(output);

end;procedure outit;

begin

close(input);

close(output);

halt;

end;

procedure readdata;

var

i,num,x:longint;

begin

read(n);

num:=0;

for i:=1 to 5 do

begin

read(x);

while x<>0 do

begin

inc(num);

map[num,i]:=x;

read(x);

end;

num:=0;

end;

{ for i:=1 to 7 do

begin

for x:=1 to 5 do

if map[i,x]=0 then write(‘  ‘)

else write(map[i,x],‘ ‘);

writeln;

end;}

end;

procedure percent30;

var

i:longint;

flag:longint;

num:longint;

k:array[1..3] of longint;//记录flag=3时的颜色状态

begin

flag:=0;

for i:=1 to 5 do

if map[1,i]<>0 then

inc(flag);//flag为1,2,4和5时必定无法消完

if flag in [1,2,4,5] then

begin

writeln(-1);

outit;

end;

//处理剩下flag=3的情况

num:=0;

for i:=1 to 5 do

if map[1,i]<>0 then

begin

inc(num);

k[num]:=map[1,i];

end;

if not((k[1]=k[2])or(k[2]=k[3])or(k[1]=k[3])) then

begin

writeln(-1);

outit;

end;

//剩下只有第一行有三个并且颜色相同 且要在刚好steps步数下完成

//(由于初始状态无可消除的 所以只有三种情况 打表。。。)

for i:=1 to 5 do if map[1,i]<>0 then map[1,i]:=1 else map[1,i]:=0;//把有颜色的处理成1

//三种情况分别为1 1 0 1 0      1 1 0 0 1     1 0 1 0 1

if (map[1,1]=1)and(map[1,2]=1)and(map[1,3]=0)and(map[1,4]=1)and(map[1,5]=0) then

begin//1 1 0 1 0

if n=1 then

begin

writeln(‘3 0 -1‘);

outit;

end

else if n=2 then

begin

writeln(‘1 0 1‘);

writeln(‘0 0 1‘);

outit;

end

else if n=4 then

begin

writeln(‘3 0 1‘);

writeln(‘1 0 1‘);

writeln(‘0 0 1‘);

writeln(‘1 0 1‘);

outit;

end

else begin

writeln(-1);

outit;

end;

end

else if (map[1,1]=1)and(map[1,2]=1)and(map[1,3]=0)and(map[1,4]=0)and(map[1,5]=1) then

begin//1 1 0 0 1

if n=2 then

begin

writeln(‘4 0 -1‘);

writeln(‘3 0 -1‘);

outit;

end

else if n=3 then

begin

writeln(‘1 0 1‘);

writeln(‘0 0 1‘);

writeln(‘4 0 -1‘);

outit;

end

else if n=4 then

begin

writeln(‘1 0 1‘);

writeln(‘0 0 1‘);

writeln(‘2 0 1‘);

writeln(‘1 0 1‘);

outit;

end

else begin

writeln(-1);

outit;

end;

end

else if (map[1,1]=1)and(map[1,2]=0)and(map[1,3]=1)and(map[1,4]=0)and(map[1,5]=1) then

begin//1 0 1 0 1

if n=2 then

begin

writeln(‘0 0 1‘);

writeln(‘4 0 -1‘);

outit;

end

else if n=3 then

begin

writeln(‘0 0 1‘);

writeln(‘2 0 1‘);

writeln(‘1 0 1‘);

outit;

end

else begin

writeln(-1);

outit;

end;

end

else begin

writeln(-1);

outit;

end;

end;

procedure main;

var

i:longint;

flag:boolean;

begin

flag:=true;

for i:=1 to 5 do

if map[2,i]<>0 then

flag:=false;//flag=true时表示第二行没有方块 即只有第一行有方块

if flag then percent30;//处理30%的数据  都在最下面一行 即map[1,1~5]

if not flag then writeln(-1);//剩下的直接cheat -1

end;

begin

//init;

readdata;

main;

//outit;

end.

满分做法:

program

type

state=array[1..10,1..10] of longint;

arr=array[1..10] of longint;

var

map:state;len:arr;

p:array[1..10] of record x,y,z:longint;end;

n,i,j,tmp,t,tt,pt : longint;

procedure doit(x,y,g:longint;var map:state; var len:arr);

var

tmp,i,j,k,color,t:longint; flag:boolean;

begin

if g=-1 then

begin tmp:=map[x,y];map[x,y]:=map[x-1,y];map[x-1,y]:=tmp;end

else

if g=1 then

begin tmp:=map[x,y];map[x,y]:=map[x+1,y];map[x+1,y]:=tmp;end;

if map[x,y]=0 then

begin

for j:=y downto 1 do

if map[x+g,j]=0 then break;

map[x+g,j]:=map[x+g,y]; map[x+g,y]:=0;len[x+g]:=j;

end;

repeat

flag:=false;

for i:=1 to 5 do

for j:=1 to 7 do

begin

if map[i,j]=0 then continue;

color:=map[i,j];

if i<=3 then

begin

t:=1;

for k:=1 to 2 do

if map[i+k,j]=color then inc(t);

if t=3 then

begin for k:=0 to 2 do map[i+k,j]:=0;flag:=true;end;

end;

if j>=3 then

begin

t:=1;

for k:=1 to 2 do if map[i,j-k]=color then inc(t);

if t=3 then

begin for k:=0 to 2 do map[i,j-k]:=0;flag:=true;end;

end;

end;

if flag then

begin

for i:=1 to 5 do

begin

for j:=1 to 7 do if map[i,j]=0 then break;

for k:=j+1 to 7 do if map[i,k]<>0 then break;

if map[i,k]=0 then continue

else

begin

move(map[i,k],map[i,j],4*(len[i]-k+1));

for j:=j+len[i]-k+1 to 7 do map[i,j]:=0;

end;

end;

for i:=1 to 5 do

begin

for j:=1 to 7 do if map[i,j]=0 then break;

len[i]:=j-1;

end;

end;

until not flag;

end;

procedure dfs(max,depth:integer;map:state;len:arr);

var  bak:state; bak2:arr;i,j,zz,way:longint;

begin

zz:=0;

for i:=1 to 5 do inc(zz,len[i]);

if zz=0 then

begin

for i:=1 to pt do writeln(p[i].x-1,‘ ‘,p[i].y-1,‘ ‘,p[i].z);  close(input);close(output);halt;

end;

if depth>max then exit;

way:=0; inc(tt); bak:=map; bak2:=len;

if tt>40000000 then begin writeln(‘-1‘);close(input);close(output);halt;end;

for i:=1 to 5 do

for j:=1 to len[i] do

begin

if i<5 then

begin

doit(i,j,1,map,len);inc(pt);

p[pt].x:=i; p[pt].y:=j; p[pt].z:=1;

dfs(max,depth+1,map,len);

dec(pt); map:=bak; len:=bak2;

end;

if i>1 then

begin

doit(i,j,-1,map,len);inc(pt);          p[pt].x:=i;p[pt].y:=j;p[pt].z:=-1;

dfs(max,depth+1,map,len);         dec(pt); map:=bak; len:=bak2;

end;

end;

end;

begin

assign(input,‘mayan.in‘);reset(input);  assign(output,‘mayan.out‘);rewrite(output);

readln(n);

for i:=1 to 5 do

begin

t:=0;

while not eoln do

begin

read(tmp);

if tmp<>0 then begin inc(t);map[i,t]:=tmp;end;

len[i]:=t;

end;

readln;

end;

dfs(n,1,map,len);

writeln(‘-1‘);

close(input); close(output);

end.

program mayan;

typetyy=array[0..10,0..10] of longint;

varf:tyy;

n,i,a,b:longint;

x,y,z:array[0..10] of longint;

function jiancha(ff:tyy):boolean;                              //检查最低层是否都消去

vari,j:longint;

begin

for i:=0 to 4 do

if ff[i,0]<>0 then exit(false);

exit(true)

end;

procedure print;

vari:longint;

begin

for i:=1 to n do

writeln(x[i],‘ ‘,y[i],‘ ‘,z[i]);

{close(input); close(output);}

halt;                                          //若有多种方案则以x为第一关键字按字典序输出,因为搜索时按x从0到4搜索的,故找到第一种方案是可以直接退出程序

end;

procedure dfs(k:longint; ff:tyy);

forward;

procedure check(k:longint; ff:tyy);

varbt:array[0..4,0..7] of boolean;

boo:boolean;

i,j,kk,t:longint;

begin

boo:=false;

while (not boo) do             //判断是否能下降,若没有下降则说明没有能消除的方块

begin

for i:=0 to 4 do for j:=0 to 7 do bt[i,j]:=false;               //初始化bt,记录能否消除

for i:=0 to 4 do for j:=0 to 7 do                              //消除三个连续相同的

begin

if ff[i,j]=0 then continue;

if (ff[i,j]=ff[i,j+1])and(ff[i,j+1]=ff[i,j+2])and(ff[i,j]<>0)then

begin

bt[i,j]:=true;

bt[i,j+1]:=true;

bt[i,j+2]:=true;

end;

if (ff[i,j]=ff[i+1,j])and(ff[i+1,j]=ff[i+2,j])and(ff[i,j]<>0)then

begin

bt[i,j]:=true;

bt[i+1,j]:=true;

bt[i+2,j]:=true;

end;

end;

for i:=0 to 4 do for j:=0 to 7 do if bt[i,j] then ff[i,j]:=0;

boo:=true;

for i:=0 to 4 do                                                        //下降

for j:=0 to 7 do

if ff[i,j]=0 then

begin

t:=j;

while (t<=7)and(ff[i,t]=0) do inc(t);

if t>7 then break;

for kk:=0 to t-j do

begin

ff[i,j+kk]:=ff[i,t+kk];

ff[i,t+kk]:=0;

end;

boo:=false;

end;

if boo then break;

end;

if (k<>n+1)and(jiancha(ff)) then exit;                //若不是在规定步数走完,则退出

if (k=n+1)and(jiancha(ff)) then print;                //若恰好在规定步数消完,则输出

dfs(k,ff);

end;

procedure dfs(k:longint; ff:tyy);

vari,j,tt:longint;

begin

ifk>n then exit;

for j:=0 to 4 do

for i:=0 to 7 do

begin

if (ff[j,i]=0)then break;

if (ff[j-1,i]=0)and(j<>0)and(ff[j,i]<>ff[j-1,i]) then          //若可以交换,则尝试交换

begin

x[k]:=j;  y[k]:=i;  z[k]:=-1;

tt:=ff[j,i];  ff[j,i]:=ff[j-1,i];  ff[j-1,i]:=tt;

check(k+1,ff);

tt:=ff[j,i];  ff[j,i]:=ff[j-1,i];  ff[j-1,i]:=tt;

x[k]:=0;  y[k]:=0;  z[k]:=0;

end;

if j=4 then continue;          //若搜索到最后一列,则不能向右移动,退出本次循环

if ff[j,i]=ff[j+1,i] then continue;

x[k]:=j; y[k]:=i; z[k]:=1;

tt:=ff[j,i]; ff[j,i]:=ff[j+1,i]; ff[j+1,i]:=tt;

check(k+1,ff);

tt:=ff[j,i]; ff[j,i]:=ff[j+1,i]; ff[j+1,i]:=tt;

x[k]:=0; y[k]:=0; z[k]:=0;

end;

end;

begin

{assign(input,‘mayan.in‘);reset(input);

assign(output,‘mayan.out‘);rewrite(output);}

readln(n);

for i:=0 to 4 do                                                     //读入数据

begin

b:=-1;

repeat

read(a);

inc(b);

f[i,b]:=a;

until a=0;

end;

x[0]:=-1; y[0]:=-1; z[0]:=-2;                                 //将x、y、z数组初始化

dfs(1,f);

writeln(‘-1‘);                                           //若没有解决方案,输出-1

{close(input);

close(output);}

end.

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

时间: 2024-10-06 03:04:40

NOIP2011 Mayan游戏 题解的相关文章

NOIp2011 mayan游戏

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

NOIP2011 Mayan游戏(搜索)

第一反应是搜索题,想了一下如果用BFS的话,由于状态过多,可能超内存,因此我用的DFS. 这里我们讨论一下剪枝条件: 如果当前状态有一种颜色的数量小于3,那么这种颜色就无法被消除,因此我们可以提前退出迭代. 如果两个连着的方块颜色是相同的话,我们不用交换. 如果两个非空的方块交换,我们只用考虑左边那个方块右移,而不用考虑右边方块左移的情况,这样就能做到右移优先. 如果一个方块是空的,它的右边非空,我们就只用考虑它右边的方块左移,当枚举到它右边方块的时候也不需要再考虑左移的情况. 注意下落清除方块

【noip2011】【codevs1136】Mayan游戏

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

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

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

洛谷 P1312 Mayan游戏

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

$Mayan$游戏

\(Mayan\)游戏 好啊,一年(半年)来的梦魇,终于结束了. 其实我从来没料到整体竟然会如此暴力--做的时候机房里冷得很,感觉晕晕乎乎地做完了,晕晕乎乎地调了好久,晕晕乎乎地听(看了题解的)\(qcr\)给我讲怎么优化代码量,怎么剪枝. 每次搜索要保留本次的状态,这是比较好想的,我也成功的想到了.但是问题是我们不能单纯地用一个二维数组来\(copy\),需要记录步数,不然就会错误\(copy\_back\).于是最终我们需要一个三维数组来记录.后半段是\(qcr\)告诉我的. 大概就是--我

codevs 1512 转向游戏 题解

Codevs 1512转向游戏 题解 时间限制: 1 s 空间限制: 1000 KB 题目等级 : 白银 Silver 题解 题目描述 Description 小明自认为方向感很好,请小红来测试.小红先让小明面对北方立正站好,然后发出"向左转""向右转"或"向后转"的命令.每个命令执行后,小明都正确地说出了他面对的方向.小红的命令共N个(1≤n≤10000),请你统计小明说[南]的次数. 命令是以数字方式表达: 0---向左转 1---向右转 2

noip提高组2011 Mayan游戏

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

bzoj 1874 取石子游戏 题解 &amp; SG函数初探

[原题] 1874: [BeiJing2009 WinterCamp]取石子游戏 Time Limit: 5 Sec  Memory Limit: 162 MB Submit: 334  Solved: 122 [Submit][Status] Description 小H和小Z正在玩一个取石子游戏. 取石子游戏的规则是这样的,每个人每次可以从一堆石子中取出若干个石子,每次取石子的个数有限制,谁不能取石子时就会输掉游戏. 小H先进行操作,他想问你他是否有必胜策略,如果有,第一步如何取石子. In