蓝桥杯---A Dicey Problem---BFS

31 篇文章 1 订阅
7 篇文章 0 订阅

试题 算法训练 A Dicey Problem

资源限制

  时间限制:1.0s 内存限制:256.0MB


问题描述

  图1中3*3的网格是一个骰子地图。 一个标准的六面骰子需要在地图上移动(图2是一个标准六面骰子的展开图)。 每张地图有一个规定的初始位置和一个初始的骰子放置方式。在图1中,初始位置是第一行第二列——写着“2”的位置。假设你从地图的底边上观察,骰子的初始放置方式是底面(贴在地图上的那一面)是”2”,顶面(与底面相对的那一面)是“5”,”1”面向你。
在这里插入图片描述

  你可以通过沿着骰子的一条边转动来将它移动到地图上水平或是竖直方向上相邻的格子上。假设当前骰子顶面的数字为x,那么你只能将它移动到写着x的格子上,或者画着星星图案的格子上。我们的最终目标是找到一条路径,使得骰子能从起点出发,最后又回到起点。
  举个例子,在图1所示的地图中,一开始你有两种可行的移动方式——向下或者向左。由于此时骰子顶面所示的数字为”5”,当前格子下方的格子上写的数字也是”5”,因此向下移动骰子是可行的;因为当前位置左边的格子画着星星图案,因此向左移动是可行的。如果第一步选择向下移动,那么骰子朝上一面的图案会变成”6”,此时你可以向右或者向下移动骰子。如果第一步选择向左移动,那么骰子顶面的数字会变成3,这种情况下,任何移动方式都是不可行的。
  我们用 (行号, 列号) 的方式来标记格子。行号从1开始,从上向下递增;列号从1开始,从左向右递增。这样,在上述例子中一个可行的解可以表示为:(1,2), (2,2), (2,3), (3,3), (3,2), (3,1), (2,1), (1,1), (1,2)。图3中展示了一个更加困难的例子。

在这里插入图片描述

  在本题中,你需要编写程序对输入中给定的地图进行求解。每张地图可能存在一个唯一的解或者无解。也就是说,对于某一张地图,如果有解,你可以认为它只有一个解。对于每张地图,你需要输出一解或者一个信息表示无解。


输入格式

  第一行包含6个用空格分隔的整数R, C, x0, y0, T, F,分别表示地图的行数、列数、初始位置行号、初始位置列号、初始状态下顶面的数字、初始状态下面向你的数字。
  接下来的R行,每行包含C个空格分隔的整数,定义了这个地图。如果某个数是0,则表示对应的格子为空(不可以被走到);如果某个数是-1,则表示对应单元格是画着星星图案的单元格;其余情况下,这个数表示对应格子上写的数字。


输出格式

  若该地图无解,则输出一行“No Solution Possible” (不包含引号)。否则,你应该输出一个逗号分隔的位置序列,表示骰子依次经过的位置。注意你输出的第一个位置和最后一个位置应该是相同的(起始位置已在输入中规定),位置的格式如上文所示。除了最后一行外,每行应该包含九个位置。另外你的输出中不应包含空格。


样例输入

3 3 1 2 5 1
-1 2 4
5 5 6
6 -1 -1


样例输出

(1,2),(2,2),(2,3),(3,3),(3,2),(3,1),(2,1),(1,1),(1,2)


样例输入

4 7 2 6 3 6
6 4 6 0 2 6 4
1 2 -1 5 3 6 1
5 3 4 5 6 4 2
4 1 2 0 3 -1 6


样例输出

(2,6),(2,5),(2,4),(2,3),(2,2),(3,2),(4,2),(4,1),(3,1),
(2,1),(2,2),(2,3),(2,4),(2,5),(1,5),(1,6),(1,7),(2,7),
(3,7),(4,7),(4,6),(3,6),(2,6)


样例输入

3 3 1 1 2 4
2 2 3
4 5 6
-1 -1 -1


样例输出

No Solution Possible


数据规模和约定

  20%的数据,R*C≤30
  100%的数据,R,C≤10,保证初始状态合法。


实现代码

#include<iostream>
#include<string>
#include<queue>
#include<map>
#include<cstring>

using namespace std;

const int maxn = 11;
// vis存在坐标(r, c)处骰子的状态(上面和前面)是否访问过。
int maxc, maxr, m[maxn][maxn], vis[maxn][maxn][7][7]; 
//逆时针存top面是行标为i时的侧面4个点数
int a[7][4] = { {0,0,0,0} ,{2,4,5,3}, {6,4,1,3}, {6,2,1,5}, {6,5,1,2}, {6,3,1,4}, {2,3,5,4} };

string num_to_str(int num) { //数字转为字符串
	string str = "";
	while (num) {
		char a = '0' + num % 10;
		str = a + str;
		num /= 10;
	}
	return str;
}

struct Node{
	map<string, int> face; //存放每一面存放的点数
	string str;
	int r, c, cnt;
	Node(int x, int y, string par_str, map<string, int> a, int new_cnt) {
		r = x, c = y, cnt = new_cnt;
		if (cnt) {
			par_str += ",";
			if (cnt % 9 == 0) par_str += "\n"; // 每9个隔一行
		}
		str = par_str + "(" + num_to_str(r) + "," + num_to_str(c) + ")";
		face = a;
	}
	string get_str() { return str; }
};

map<string, int> turn_down(map<string, int> a) { //向下转动
	int tmp = a["top"];
	a["top"] = a["back"];
	a["back"] = a["down"];
	a["down"] = a["front"];
	a["front"] = tmp;
	return a;
}

map<string, int> turn_up(map<string, int> a) { //向上转动
	int tmp = a["top"];
	a["top"] = a["front"];
	a["front"] = a["down"];
	a["down"] = a["back"];
	a["back"] = tmp;
	return a;
}

map<string, int> turn_left(map<string, int> a) { //向左转动
	int tmp = a["top"];
	a["top"] = a["right"];
	a["right"] = a["down"];
	a["down"] = a["left"];
	a["left"] = tmp;
	return a;
}

map<string, int> turn_right(map<string, int> a) { //向右转动
	int tmp = a["top"];
	a["top"] = a["left"];
	a["left"] = a["down"];
	a["down"] = a["right"];
	a["right"] = tmp;
	return a;
}

void bfs(int x, int y, int t, int f) {
	queue<Node> q;
	map<string, int> face;
	face["top"] = t, face["down"] = 7 - t;
	face["front"] = f, face["back"] = 7 - f;
	for (int i = 0; i < 4; i++) {
		if (a[t][i] == f) {
			face["left"] = a[t][(i + 1) % 4], face["right"] = a[t][(i + 3) % 4];
			break;
		}
	}
	memset(vis, 0, sizeof(vis));
	q.push(Node(x, y,"", face, 0));
	while (q.size()) {
		Node now = q.front(); q.pop();
		int r = now.r, c = now.c, top = now.face["top"], front = now.face["front"], cnt = now.cnt;
		if (vis[r][c][top][front]) continue;
		vis[r][c][top][front] = 1;
		string str = now.get_str();
		if (r == x && c == y) {
			vis[r][c][top][front] = 0; //起点不用记录,只要可以回到就可以了
			if (cnt) { //步长不为0就是重新回到
				cout << str;
				exit(0);
			}
		}
		if (m[r][c - 1] == top || m[r][c - 1] == -1) { q.push(Node(r, c - 1, str, turn_left(now.face), cnt + 1)); } // left
		if (m[r][c + 1] == top || m[r][c + 1] == -1) { q.push(Node(r, c + 1, str, turn_right(now.face), cnt + 1)); } // right
		if (m[r - 1][c] == top || m[r - 1][c] == -1) { q.push(Node(r - 1, c, str, turn_up(now.face), cnt + 1)); } // up
		if (m[r + 1][c] == top || m[r + 1][c] == -1) { q.push(Node(r + 1, c, str, turn_down(now.face), cnt + 1)); } // down
	}
	cout << "No Solution Possible" << endl;
}

int main() { 
	int x, y, t, f;
	cin >> maxr >> maxc >> x >> y >> t >> f;
	for (int i = 1; i <= maxr; i++) for (int j = 1; j <= maxc; j++) cin >> m[i][j];
	bfs(x, y, t, f);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值