洛谷 P1312 Mayan游戏
一道很烤验代码能力的题目
P1312 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 所示的局面。
输入输出格式
输入格式:
共 6 行。
第一行为一个正整数nn,表示要求游戏通关的步数。
接下来的55行,描述7 \times 57×5 的游戏界面。每行若干个整数,每两个整数之间用一个空格隔开,每行以一个00 结束,自下向上表示每竖列方块的颜色编号(颜色不多于1010种,从11开始顺序编号,相同数字表示相同颜色)。
输入数据保证初始棋盘中没有可以消除的方块。
输出格式:
如果有解决方案,输出nn行,每行包含 3 个整数x,y,g,表示一次移动,每两个整数之间用一个空格隔开,其中(x ,y)表示要移动的方块的坐标,g 表示移动的方向,1 表示向右移动,-1表示向左移动。注意:多组解时,按照x为第一关健字,y为第二关健字,1优先于-1 ,给出一组字典序最小的解。游戏界面左下角的坐标为(0 ,0)。
如果没有解决方案,输出一行,包含一个整数-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
说明
【输入输出样例说明】
按箭头方向的顺序分别为图66到图1111
样例输入的游戏局面如上面第一个图片所示,依次移动的三步是:(2 ,1 )处的方格向右移动,(3,1)处的方格向右移动,(3,0)处的方格向右移动,最后可以将棋盘上所有方块消除。
【数据范围】
对于30%的数据,初始棋盘上的方块都在棋盘的最下面一行;
对于100%的数据,0 < n≤5。
noip2011提高组day1第3题
题目分析
很明显的dfs
剪枝
1、相同颜色不交换
2、若左边不为空,不考虑向左交换。
比如(1,3)向左,也可以通过(1,2)向右交换实现。
数据声明
int c[s][y][x];第s步时,表格情况
int x[6], y[6], b[6]; 记录每一步
bool vis[7][9][7];记录需要删除的表格
dfs
for (int i = 1; i <= 5; i++) { //按序搜索可以移动的块
for (int j = 1; j <= 7; j++) {
if (c[s][j][i]) {
if (i + 1 <= 5 && c[s][j][i] != c[s][j][i + 1]) { //不越界且颜色不同向右移
x[s + 1] = i;
y[s + 1] = j;
b[s + 1] = 1;
dfs(s + 1, i, j, 1);
if (g) //g为标识符,表示是否找到正确方案
return;
}
if (i - 1 >= 1 && c[s][j][i - 1] == 0) { //左边为空向左移
x[s + 1] = i; //向左移时,x,y也要更新
y[s + 1] = j;
b[s + 1] = -1;
dfs(s + 1, i, j, -1);
if (g)
return;
}
}
}
}
移动
for (int i = 1; i <= 5; ++i) //复制上一步的表格
for (int j = 1; j <= 7; j++)
c[s][j][i] = c[s - 1][j][i];
if (c[s][dy][dx + db]) //交换
swap(c[s][dy][dx], c[s][dy][dx + db]);
else { //移动到空格
c[s][dy][dx + db] = c[s][dy][dx];
c[s][dy][dx] = 0;
int p = dy - 1; //移动后掉落
while (p && !c[s][p][dx + db]) {
swap(c[s][p][dx + db], c[s][p + 1][dx + db]);
p--;
}
p = dy + 1; //原列上方的格子下落
while (p < 8 && c[s][p][dx]) {
swap(c[s][p - 1][dx], c[s][p][dx]);
p++;
}
}
搜索可以消除方块
int search(int s) {
int ans = 0;
for (int i = 1; i <= 5; i++) { //清空
for (int j = 1; j <= 7; j++) {
vis[s][j][i] = false;
if (c[s][j][i])
ans++;
}
}
int flag = 0;
for (int i = 1; i <= 5; i++) { //纵向搜索
for (int j = 1; j <= 5; j++) {
if (!c[s][j][i])
break;
int cnt = 1;
while (c[s][j][i] == c[s][j + 1][i]) {
cnt++;
j++;
}
if (cnt >= 3) { //相同超过三个标记
flag = 1;
for (int k = cnt - 1; k >= 0; k--)
vis[s][j - k][i] = true;
}
}
}
for (int j = 1; j <= 7; j++) { //横向搜索
for (int i = 1; i <= 3; i++) {
if (!c[s][j][i])
continue;
int cnt = 1;
while (c[s][j][i] == c[s][j][i + 1]) {
cnt++;
i++;
}
if (cnt >= 3) { //相同超过三个,标记
flag = 1;
for (int k = cnt - 1; k >= 0; k--)
vis[s][j][i - k] = true;
}
}
}
if (flag == 0 || ans == 1 || ans == 2)
return (0);
for (int i = 1; i <= 5; i++) { //删除方块
for (int j = 1; j <= 7; j++)
if (vis[s][j][i])
c[s][j][i] = 0, ans--;
}
if (!ans)
return 2;
return 1;
}
方块掉落
void change(int s) {
for (int i = 1; i <= 5; i++) {
for (int j = 2; j <= 7; j++) {
if (c[s][j][i]) {
int p = j - 1;
while (!c[s][p][i] && p) {
swap(c[s][p][i], c[s][p + 1][i]);
p--;
}
}
}
}
}
完整代码
#include <iostream>
#include <cstdio>
using namespace std;
#pragma warning (disable:4996)
int n; bool g = false;
int c[7][9][7], x[6], y[6], b[6];
bool vis[7][9][7];
void Print(int s) {
cout << s << ":\n";
cout << x[s] << ' ' << y[s] << ' ' << b[s] << '\n';
for (int j = 7; j >= 1; j--) {
for (int i = 1; i <= 5; i++) {
printf("%3d", c[s][j][i]);
}
putchar('\n');
}
putchar('\n');
}
int search(int s) {
int ans = 0;
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= 7; j++) {
vis[s][j][i] = false;
if (c[s][j][i])
ans++;
}
}
int flag = 0;
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= 5; j++) {
if (!c[s][j][i])
break;
int cnt = 1;
while (c[s][j][i] == c[s][j + 1][i]) {
cnt++;
j++;
}
if (cnt >= 3) {
flag = 1;
for (int k = cnt - 1; k >= 0; k--)
vis[s][j - k][i] = true;
}
}
}
for (int j = 1; j <= 7; j++) {
for (int i = 1; i <= 3; i++) {
if (!c[s][j][i])
continue;
int cnt = 1;
while (c[s][j][i] == c[s][j][i + 1]) {
cnt++;
i++;
}
if (cnt >= 3) {
flag = 1;
for (int k = cnt - 1; k >= 0; k--)
vis[s][j][i - k] = true;
}
}
}
if (flag == 0 || ans == 1 || ans == 2)
return (0);
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= 7; j++)
if (vis[s][j][i])
c[s][j][i] = 0, ans--;
}
if (!ans)
return 2;
return 1;
}
void change(int s) {
for (int i = 1; i <= 5; i++) {
for (int j = 2; j <= 7; j++) {
if (c[s][j][i]) {
int p = j - 1;
while (!c[s][p][i] && p) {
swap(c[s][p][i], c[s][p + 1][i]);
p--;
}
}
}
}
}
void dfs(int s, int dx, int dy, int db) {
for (int i = 1; i <= 5; ++i)
for (int j = 1; j <= 7; j++)
c[s][j][i] = c[s - 1][j][i];
if (c[s][dy][dx + db])
swap(c[s][dy][dx], c[s][dy][dx + db]);
else {
c[s][dy][dx + db] = c[s][dy][dx];
c[s][dy][dx] = 0;
int p = dy - 1;
while (p && !c[s][p][dx + db]) {
swap(c[s][p][dx + db], c[s][p + 1][dx + db]);
p--;
}
p = dy + 1;
while (p < 8 && c[s][p][dx]) {
swap(c[s][p - 1][dx], c[s][p][dx]);
p++;
}
}
int ops;
while (ops = search(s)) {
if (ops == 2) {
n = s;
g = true;
return;
}
else
change(s);
}
if (s == n)
return;
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= 7; j++) {
if (c[s][j][i]) {
if (i + 1 <= 5 && c[s][j][i] != c[s][j][i + 1]) {
x[s + 1] = i;
y[s + 1] = j;
b[s + 1] = 1;
dfs(s + 1, i, j, 1);
if (g)
return;
}
if (i - 1 >= 1 && c[s][j][i - 1] == 0) {
x[s + 1] = i;
y[s + 1] = j;
b[s + 1] = -1;
dfs(s + 1, i, j, -1);
if (g)
return;
}
}
}
}
}
int main() {
scanf("%d", &n);
int r, k;
for (int i = 1; i <= 5; i++) {
k = 0;
while (~scanf("%d", &r) && r)
c[0][++k][i] = r;
}
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= 7; j++) {
if (c[0][j][i]) {
if (i + 1 <= 5 && c[0][j][i] != c[0][j][i + 1]) {
x[1] = i;
y[1] = j;
b[1] = 1;
dfs(1, x[1], y[1], 1);
if (g)break;
}
if (i - 1 >= 1 && c[0][j][i - 1] == 0) {
x[1] = i;
y[1] = j;
b[1] = -1;
dfs(1, x[1], y[1], -1);
if (g)break;
}
}
}
if (g)
break;
}
if (g) {
for (int i = 1; i <= n; i++)
printf("%d %d %d\n", x[i] - 1, y[i] - 1, b[i]);
}
else
printf("%d\n", -1);
}