NOIP 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。
限制
3s
提示
超复杂爆搜,没别的法了。。。。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxx=10,maxy=20,maxc=20; 4 int n,c;//n表示步数,c表示方块颜色数 5 int a[maxx][maxy];//存图 6 int cnt[maxc];//记录每种颜色方块的个数 7 bool f[maxx][maxy]; 8 int ans[maxx][3]; 9 10 void fall(int x){//第 x行下落构图 11 for(int i=0;i<7;i++){ 12 if(a[x][i]==0){ 13 int j=i+1; 14 while(j<7&&a[x][j]==0) 15 j++; 16 if(j==7) 17 return; 18 else swap(a[x][i],a[x][j]); 19 } 20 } 21 } 22 23 bool clear(){ 24 25 bool flag=false; 26 for(int i=0;i<5;i++){//横坐标 27 for(int j=0;j<7;j++){//纵坐标 28 if(a[i][j]==0) 29 continue; 30 if(i<3&&a[i][j]==a[i+1][j]&&a[i][j]==a[i+2][j]){//横向消 31 f[i][j]=true; 32 f[i+1][j]=true; 33 f[i+2][j]=true; 34 } 35 if(j<5&&a[i][j]==a[i][j+1]&&a[i][j]==a[i][j+2]){//纵向消 36 f[i][j]=true; 37 f[i][j+1]=true; 38 f[i][j+2]=true; 39 } 40 } 41 } 42 43 for(int i=0;i<5;i++){ 44 for(int j=0;j<7;j++){ 45 if(f[i][j]==true){//(i,j)需要被消掉 46 flag=true; 47 cnt[a[i][j]]--;//颜色减少 48 a[i][j]=0; 49 f[i][j]=false; 50 } 51 } 52 } 53 54 for(int i=0;i<5;i++) 55 fall(i);//消完之后再下落 56 57 return flag;//返回true说明还有可能继续消 58 } 59 60 int check(){//输出方块颜色最少的那个颜色个数 61 int minc=0; 62 for (int i=1;i<=c;i++){ 63 if(cnt[i]!=0){ 64 if (minc==0||minc>cnt[i]){ 65 minc=cnt[i]; 66 } 67 } 68 } 69 return minc; 70 } 71 72 void print(){//输出答案 73 74 for (int i = 1; i <= n; i++) 75 printf("%d %d %d\n", ans[i][0], ans[i][1], ans[i][2]); 76 77 exit(0);//结束程序 78 } 79 void dfs(int move){//move 移动步数 80 81 int mem[maxx][maxy]; 82 int memc[maxc]; 83 memcpy(mem,a,sizeof(a)); 84 memcpy(memc,cnt,sizeof(cnt)); 85 86 for(int i=0;i<5;i++){//横坐标 87 for(int j=0;a[i][j]!=0&&j<7;j++){//纵坐标 88 for (int k=1;k>=-1;k-=2){//右移左移两种情况,先算右移 89 if(i+k>=0&&i+k<5){//判断边界 90 if ((k==-1&&a[i-1][j]!=0)||a[i][j]==a[i+k][j])//如果左边有方块或者相邻的方块同色,不需考虑 91 continue; 92 93 ans[move][0]=i;//记录移动信息 94 ans[move][1]=j; 95 ans[move][2]=k; 96 swap(a[i][j], a[i+k][j]);//交换 97 98 fall(i);//处理交换后的影响 99 fall(i+k); 100 101 while (clear()==true);//消去再组合 102 int tmp=check();//tmp是当前颜色最少的方块的个数 103 if(move==n){//n步 104 if(tmp==0)//方块完 105 print();//满足条件,输出 106 } 107 else if(tmp>2)//找下一步 108 dfs(move+1); 109 110 memcpy(a,mem,sizeof(mem));//相当于回溯,把操作之前的恢复原状 111 for (int i = 1; i <= c; i++) 112 cnt[i] = memc[i]; 113 } 114 } 115 } 116 } 117 118 } 119 120 int main(){ 121 scanf("%d", &n); 122 memset(a, 0, sizeof(a)); 123 memset(cnt, 0, sizeof(cnt)); 124 memset(ans, 0, sizeof(ans)); 125 memset(f, 0, sizeof(f)); 126 c = 0; 127 int tmp; 128 for (int i = 0; i < 5; i++) 129 for (int j = 0; j <= 7; j++){ 130 scanf("%d", &tmp); 131 if (tmp == 0) 132 break; 133 a[i][j] = tmp; 134 c = max(c, tmp); 135 cnt[tmp]++;//每种方块的数量 136 } 137 dfs(1); 138 printf("-1\n");//能走到这一步说明没走print(),即消不完 139 return 0; 140 }