洛谷 P1312 Mayan游戏

洛谷  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);
}

结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值