洛谷P1312 [NOIP2011提高组Day1T3]Mayan游戏
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 所示的局面。
输入输出格式
输入格式:输入文件mayan.in,共 6 行。
第一行为一个正整数n ,表示要求游戏通关的步数。
接下来的5 行,描述 7*5 的游戏界面。每行若干个整数,每两个整数之间用一个空格隔开,每行以一个0 结束,自下向上表示每竖列方块的颜色编号(颜色不多于10种,从1 开始顺序编号,相同数字表示相同颜色)。
输入数据保证初始棋盘中没有可以消除的方块。
输出格式:输出文件名为mayan.out。
如果有解决方案,输出 n 行,每行包含 3 个整数x,y,g ,表示一次移动,每两个整数之间用一个空格隔开,其中(x ,y)表示要移动的方块的坐标,g 表示移动的方向,1 表示向右移动,-1表示向左移动。注意:多组解时,按照 x 为第一关健字,y 为第二关健字,1优先于-1 ,给出一组字典序最小的解。游戏界面左下角的坐标为(0 ,0 )。
如果没有解决方案,输出一行,包含一个整数-1。
输入输出样例
3 1 0 2 1 0 2 3 4 0 3 1 0 2 4 3 4 0
2 1 1 3 1 1 3 0 1
说明
【输入输出样例说明】
按箭头方向的顺序分别为图6 到图11
样例输入的游戏局面如上面第一个图片所示,依次移动的三步是:(2 ,1 )处的方格向右移动,(3,1 )处的方格向右移动,(3 ,0)处的方格向右移动,最后可以将棋盘上所有方块消除。
【数据范围】
对于30% 的数据,初始棋盘上的方块都在棋盘的最下面一行;
对于100%的数据,0 < n≤5 。
noip2011提高组day1第3题
【题解】
阻止我AK掉人品的一道题。。不过在考场上可能多1h就能A了吧。。
留了两个半小时敲这个题,时间长感觉有点松懈了。。
还有两个月NOIP,两个月后可能场上可A?
这里有三个剪枝
1、右边左拉等价左边右拉,所以只有左边为0时才左拉,否则右拉
2、若右拉的格子颜色等于他的右边, 交换就没有意义了
3、某种颜色>=1<=2,方案不可行
注意消除的时候,横着消的地方要同时处理竖着消,竖着消的地方要
同时处理横着消,可能有2~4个点卡这个地方?
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #define max(a, b) ((a) > (b) ? (a) : (b)) 6 7 inline void read(int &x) 8 { 9 x = 0;char ch = getchar(), c = ch; 10 while(ch < '0' || ch > '9')c = ch, ch = getchar(); 11 while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar(); 12 if(c == '-')x = -x; 13 } 14 15 int ma, g[9][6], flag; 16 17 char dir[10]; 18 int ansx[10], ansy[10]; 19 20 struct Node 21 { 22 int g[9][6], re, num[11]; 23 Node() 24 { 25 re = 0; 26 memset(g, 0, sizeof(g)); 27 } 28 }; 29 inline void put(Node a) 30 { 31 for(register int i = 1;i <= 7;++ i) 32 { 33 for(register int j = 1;j <= 5;++ j) 34 printf("%d ", a.g[i][j]); 35 putchar('\n'); 36 } 37 putchar('\n'); 38 putchar('\n'); 39 } 40 inline void swap(int &a, int &b) 41 { 42 int tmp = a;a = b;b = tmp; 43 } 44 45 int del(int x, int y, Node& tmp) 46 { 47 //左右删除 48 int l = y, r = y; 49 int color = tmp.g[x][y]; 50 while(color == tmp.g[x][l]) -- l; 51 ++ l; 52 while(color == tmp.g[x][r]) ++ r; 53 -- r; 54 if(r - l + 1 >= 3) 55 { 56 for(register int i = l;i <= r;++ i) 57 tmp.g[x][i] = 0; 58 tmp.re -= (r - l + 1); 59 tmp.num[color] -= (r - l + 1); 60 for(register int i = l;i <= r;++ i) 61 { 62 tmp.g[x][i] = color; 63 ++ tmp.re; 64 ++ tmp.num[color]; 65 int up = x, down = x; 66 while(color == tmp.g[up][i])-- up; 67 ++ up; 68 while(color == tmp.g[down][i])++ down; 69 -- down; 70 if(down - up + 1 >= 3) 71 { 72 for(register int j = up;j <= down;++ j) 73 tmp.g[j][i] = 0; 74 tmp.re -= (down - up + 1); 75 tmp.num[color] -= (down - up + 1); 76 } 77 else -- tmp.re, tmp.g[x][i] = 0, --tmp.num[color]; 78 } 79 return 1; 80 } 81 82 //上下 83 int up = x, down = x; 84 while(color == tmp.g[up][y])-- up; 85 ++ up; 86 while(color == tmp.g[down][y])++ down; 87 -- down; 88 if(down - up + 1 >= 3) 89 { 90 for(register int i = up;i <= down;++ i) 91 tmp.g[i][y] = 0, --tmp.num[color]; 92 tmp.re -= (down - up + 1); 93 for(register int i = up;i <= down;++ i) 94 { 95 ++ tmp.re, tmp.g[i][y] = color, ++tmp.num[color]; 96 int l = y, r = y; 97 while(tmp.g[i][l] == color)-- l; 98 ++ l; 99 while(tmp.g[i][r] == color)++ r; 100 -- r; 101 if(r - l + 1 >= 3) 102 { 103 for(register int a = l;a <= r;++ a) 104 tmp.g[i][a] = 0; 105 tmp.re -= (r - l + 1); 106 tmp.num[color] -= (r - l + 1); 107 } 108 else -- tmp.re, tmp.g[i][y] = 0, --tmp.num[color]; 109 } 110 111 return 1; 112 } 113 return 0; 114 } 115 116 int diao(Node& tmp) 117 { 118 int re = 0; 119 for(register int j = 1;j <= 5;++ j) 120 { 121 int now = 8; 122 for(register int i = 7;i >= 1;-- i) 123 { 124 if(tmp.g[i][j] && now - 1 == i)-- now; 125 else if(tmp.g[i][j]) 126 { 127 tmp.g[now - 1][j] = tmp.g[i][j]; 128 tmp.g[i][j] = 0; 129 re = 1; 130 -- now; 131 } 132 } 133 } 134 return re; 135 } 136 int k; 137 void dfs(int step, Node now) 138 { 139 for(register int i = 1;i <= 10;++ i) 140 if(now.num[i] > 0 && now.num[i] < 3)return; 141 //如果步数走完了 142 if(step > ma) 143 { 144 //没有剩下的了 145 if(now.re == 0) 146 { 147 //输出方案 148 flag = 1; 149 for(register int i = 1;i <= ma;++ i) 150 printf("%d %d %d\n", ansy[i] - 1, ansx[i] - 1, dir[i]); 151 return; 152 } 153 return; 154 } 155 Node re; 156 157 //枚举拉点(i,j) 158 for(register int j = 1;j <= 5;++ j) 159 { 160 for(register int i = 7;i >= 1;-- i) 161 { 162 //如果(i,j)有方块 163 if(now.g[i][j]) 164 { 165 re = now; 166 if(i == 3 && j == 3 && step == 2) 167 ++ k; 168 if(i == 5 && j == 4 && step == 3) 169 ++ k; 170 if(i == 1 && j == 4 && step == 4) 171 ++ k; 172 if(i == 4 && j == 4 && step == 5) 173 ++ k; 174 //右拉 175 if(j < 5) 176 { 177 //右拉有意义 178 if(re.g[i][j] != re.g[i][j + 1]) 179 { 180 //拉动 181 swap(re.g[i][j], re.g[i][j + 1]); 182 //掉落 183 int tmp1 = i, tmp2 = j; 184 while(!re.g[tmp1 + 1][tmp2] && tmp1 + 1 <= 7) 185 { 186 swap(re.g[tmp1 + 1][tmp2], re.g[tmp1][tmp2]); 187 ++ tmp1; 188 } 189 //连环操作 190 int f = 0; 191 //如果上一次删除成功,需要重新扫描、删除 192 while(true) 193 { 194 f = 0; 195 //对于每个点(x,y),尝试进行删除 196 for(register int x = 1;x <= 7;++x) 197 { 198 for(register int y = 1;y <= 5;++ y) 199 { 200 //如果(x,y)没有颜色,就不尝试删除了 201 if(!re.g[x][y])continue; 202 //尝试删除 203 del(x, y, re); 204 } 205 } 206 //掉落 207 f = diao(re); 208 //回去,直到没有更新为止 209 if(!f)break; 210 } 211 //记录答案 212 ansx[step] = 7 - i + 1; 213 ansy[step] = j; 214 dir[step] = 1; 215 dfs(step + 1, re); 216 if(flag)return; 217 } 218 } 219 re = now; 220 if(i == 6 && j == 2 && step == 1) 221 ++ k; 222 //左拉 223 if(j > 1 && re.g[i][j - 1] == 0) 224 { 225 if(re.g[i][j] != re.g[i][j - 1]) 226 { 227 //拉动 228 swap(re.g[i][j], re.g[i][j - 1]); 229 //掉落 230 int tmp1 = i, tmp2 = j; 231 while(!re.g[tmp1 + 1][tmp2] && tmp1 + 1 <= 7) 232 { 233 swap(re.g[tmp1 + 1][tmp2], re.g[tmp1][tmp2]); 234 ++ tmp1; 235 } 236 //连环操作 237 int f = 0; 238 //如果上一次删除成功,需要重新扫描、删除 239 while(true) 240 { 241 f = 0; 242 //对于每个点(x,y),尝试进行删除 243 for(register int x = 1;x <= 7;++x) 244 { 245 for(register int y = 1;y <= 5;++ y) 246 { 247 //如果(x,y)没有颜色,就不尝试删除了 248 if(!re.g[x][y])continue; 249 //尝试删除 250 f = del(x, y, re); 251 } 252 } 253 //掉落 254 f = diao(re); 255 //回去,直到没有更新为止 256 if(!f)break; 257 } 258 //记录答案 259 ansx[step] = 7 - i + 1; 260 ansy[step] = j; 261 dir[step] = -1; 262 dfs(step + 1, re); 263 if(flag)return; 264 } 265 } 266 } 267 } 268 } 269 } 270 271 int main() 272 { 273 read(ma); 274 register int tmp, num = 0; 275 Node tt; 276 for(register int i = 1;i <= 5;++ i) 277 { 278 int j = 7; 279 read(tmp); 280 while(tmp)tt.g[j][i] = tmp, -- j, ++num, ++ tt.num[tmp], read(tmp); 281 } 282 tt.re = num; 283 dfs(1, tt); 284 if(!flag)printf("-1"); 285 return 0; 286 }