数字接龙-十五届蓝桥杯-省赛-B组C/C++<本题会超空间限制题解只是提供一个思路>

本题思路: 我是用BFS广度搜索做的, 考场上写完了, 没提交上去, 明明还有3分钟结束, 竟然提交不了了

这题的难点是游戏规则的第三与第四条, 前面两点规则很简单就不说了, 其实第三与第四条规则就是给每个顶点状态加一个地图格子标记数组与一个地图斜边标记数组就行了, 因为你会发现, 因为每走一步地图对应的状态都会发生改变, 所以, 我们必须为每个顶点设置一个地图格子标记数组与一个地图斜边标记数组, 这里看清楚是每个顶点, 而不是所有顶点共用这两个数组, 具体看代码会做详细解释, 还有一件事, 题目给出必须按照字典顺序最小输出, 这也很简单, 定义两个数组一个xx数组一个yy数组, 这两个数组的下标顺序就是题目图中给出的0 ~ 7这八个方向顺序, 顺序遍历行走就行, 默认就是最小字典序话不多说看代码, 有详细注解, 可以把代码复制到自己的编辑器上观看, csdn上面可能位置小, 观看体验不行.

#include <bits/stdc++.h>
using namespace std;
int n, k;
int g[15][15]; // 地图
int xx[8] = {-1, -1, 0, 1, 1, 1, 0, -1}; // 方向数组x, 这里的方向数组按照他给的顺序排, 自动会是最小字典序
int yy[8] = {0, 1, 1, 1, 0, -1, -1, -1}; // 方向数组y, 这里的方向数组按照他给的顺序排, 自动会是最小字典序
// 我们为什么要在为每个顶点都加一个vis与flag, 不能公共使用呢?
// 因为我们每一次不同的走向状态不一样, 所以不能公共使用vis与flag也许这个顶点状态满足当前公共vis与flag,
// 但是其他顶点不一定满足, 所以要私自每个顶点一个vis与flag特别判断
struct node {
	int x, y, vis[15][15], flag[15][15][15][15]; // (x, y)是当前两点坐标, vis是标记格子走过, flag(x1, y1)(x2, y2)表示交叉路线之前是否走过
	string s; // 保存答案
};
queue<node> que;
int main(void) {
	scanf("%d %d", &n, &k);
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < n; ++j) {
			scanf("%d", &g[i][j]);
		}
	}
	node t;
	memset(t.vis, 0, sizeof(t.vis));
	memset(t.flag, 0, sizeof(t.flag));
	t.x = 0, t.y = 0, t.s = "", t.vis[0][0] = 1;
	que.push(t);
	while (false == que.empty()) {
		t = que.front();
		que.pop();
		int x = t.x, y = t.y;
		if (n - 1 == x && n - 1 == y) {
			int f = 0; // 定义标记判断地图是不是全部被标记了
			for (int i = 0; i < n; ++i) {
				for (int j = 0; j < n; ++j) {
					if (0 == t.vis[i][j]) {
						f = 1;
						break;
					}
				}
			}
			if (1 == f) {
				// 地图没有全部标记直接对下一个顶点访问
				continue;
			} else {
				// 地图被全部标记直接输出返回结束
				cout << t.s << endl;
				return 0;
			}
		}
		for (int i = 0; i < 8; ++i) {
			int X = x + xx[i], Y = y + yy[i];
			// 首先目标顶点不能越界, 并且目标顶点不能被走过, 并且目标顶点满足数字接龙
			if (X >= 0 && X < n && Y >= 0 && Y < n && 0 == t.vis[X][Y] && ((g[x][y] + 1) % k) == g[X][Y]) {
				node tt;
				// 如果是上下左右四个方向不会有交叉冲突直接走
				if (0 == i || 2 == i || 4 == i || 6 == i) {
					memcpy(tt.vis, t.vis, sizeof(t.vis));
					memcpy(tt.flag, t.flag, sizeof(t.flag));
					tt.vis[X][Y] = 1;
					tt.x = X, tt.y = Y, tt.s = t.s + char(48 + i);
					que.push(tt);
				} else { // 但是四个斜边方向要特别判断
					int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
					if (1 == i) {
						x1 = x - 1, y1 = y, x2 = x, y2 = y + 1;
					} else if (3 == i) {
						x1 = x + 1, y1 = y, x2 = x, y2 = y + 1;
					} else if (5 == i) {
						x1 = x + 1, y1 = y, x2 = x, y2 = y - 1;
					} else if (7 == i) {
						x1 = x - 1, y1 = y, x2 = x, y2 = y - 1;
					}
					// 这里不用判断是否越界, 如果前面判断成功目标顶点存在, 那么相反的斜边一定存在
					// 所以只需要判断是否被访问过就行
					if (0 == t.flag[x1][y1][x2][y2] && 0 == t.flag[x2][y2][x1][y1]) {
						memcpy(tt.vis, t.vis, sizeof(t.vis));
						memcpy(tt.flag, t.flag, sizeof(t.flag));
						tt.x = X, tt.y = Y, tt.s = t.s + char(48 + i);
						// 前面三行赋值没什么好说, 终点说下面这个
						// 如果走到目的地这个顶点被访问vis标记
						tt.vis[X][Y] = 1;
						// 下面特别注意, 因为我最开始只标记了一条斜边, 导致会交叉走
						// 所以下面四行, 因为如果你走了这个斜边, 另外一个交叉的也不能走了, 并且因为两个方向所以两个交叉有四条走向都赋值为1
						tt.flag[x][y][X][Y] = 1;
						tt.flag[X][Y][x][y] = 1;
						tt.flag[x1][y1][x2][y2] = 1;
						tt.flag[x2][y2][x1][y1] = 1;
						que.push(tt);

					}
				}
			}
		}
	}
	// 如果没有路径输出-1
	printf("-1\n");
	return 0;
}

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值