• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
jacklee404
Never Stop!
博客园    首页    新随笔    联系   管理    订阅  订阅
拯救大兵瑞恩 拆点+双端队列BFS

拯救大兵瑞恩

题目

拯救大兵瑞恩

思路

​ 我们可以先状压DP的思维思考,\(dp[x][y][state]\) 表示了再\((x, y)\)位置有钥匙状态为\(state\)的最短距离,考虑到\(key\)最多只有\(10\)种,\(10 \times 10 \times 2^{10}\)≈\(1e6\), 足以开这么大的数组,考虑状态转移:

\[dp[x][y][state] = min(dp[x][y][state], dp[tx][ty][state] + 1) \\ dp[x][y][state | key[x][y]] = min(dp[x][y][state | key[x][y]], dp[x][y][state]) \]

​ 其中\((tx, ty)\)表示了\(x,y\)上下左右四个方向, 当然转移的时候我们还有考虑\(state\)中是否存在该🔑,来判断状态是否可以转移,另外也需要判断是否是门,但是进一步思考,图是存在环形依赖的,我们并不能通过\(dp\) 求得最短路径,所以我们需要像最优贸易,依靠SPFA或者Dijkstra来转移最短路径,由于我们考虑上述转移方程,只存在边权为\(1\)或边权为\(0\)的边,所以可以考虑双端队列广搜来求最短距离,因为依赖于Dijkstra,所以我们最先求到的一定就是最短距离, 部分时候像最优贸易一样, Dijkstra可能不对, 我们就可以用SPFA来解决来解决环形依赖问题, 具体问题具体分析,像这种正常最短路的转移,并不需要思考太多,如果定义从\(0到i\)的一条最小边权,就需要我们手动演算dijkstra是否正确。

​ 下面的代码中我对坐标轴进行了hash,用\(dp[pos][state]\)来表示一个状态。

Code

#include <iostream>
#include <vector>
#include <queue>
#include <deque>
#include <cstring>
#define ff first
#define ss second
using i64 = long long;
#define debug(x) std::cout << x << "\n"
int n, m, p, k, s;

const int N = 20, M = 400, P = 1 << 10 + 1;

int dx[] = {0, -1, 1, 0}, dy[] = {1, 0, 0, -1};

int calc(int x, int y) {
	return (x + 1) * 11 + y;
}

int key[N], door[M][M], dist[M][P];

bool st[M][P];

int bfs() {
	memset(dist, 0x3f, sizeof dist);

	std::deque<std::pair<int, int>> q1;

	q1.push_back({calc(1, 1), 0});

	dist[calc(1, 1)][0] = 0;

	while (q1.size()) {
		auto t = q1.front(); q1.pop_front();
		
		if (st[t.ff][t.ss]) continue;

		st[t.ff][t.ss] = true;

		int x = t.ff / 11 - 1, y = t.ff % 11;
		
		if (x == n && y == m) {
			return dist[t.ff][t.ss];
		}
	
		if (key[t.ff]) {
			int state = t.ss | key[t.ff];	

			if (dist[t.ff][state] > dist[t.ff][t.ss]) {
				dist[t.ff][state] = dist[t.ff][t.ss];
				q1.push_front({t.ff, state});
			}
		}

		for (int i = 0; i <= 3; i ++) {
			int tx = x + dx[i], ty = y + dy[i];

			if (tx < 1 || tx > n || ty < 1 || ty > m) continue;

			int k = calc(tx, ty);

			if (door[t.ff][k] == -1) continue;


			if (door[t.ff][k] && !(t.ss >> door[t.ff][k] - 1 & 1)) {
				continue;
			}

			if (dist[k][t.ss] > dist[t.ff][t.ss] + 1) {
				dist[k][t.ss] = dist[t.ff][t.ss] + 1;
				q1.push_back({k, t.ss});
			}
		}
	}

	return -1;
}


int main() {
	std::cin >> n >> m >> p >> k;

	for (int i = 1; i <= k; i ++) {
		int x1, y1, x2, y2, c;

		std::cin >> x1 >> y1 >> x2 >> y2 >> c;

		if (!c) c = -1;

		int p1 = calc(x1, y1), p2 = calc(x2, y2);

		door[p1][p2] = door[p2][p1] = c;
	}

	std::cin >> s;

	for (int i = 1; i <= s; i ++) {
		int x, y, q;

		std::cin >> x >> y >> q;

		key[calc(x, y)] |= 1 << q - 1;
	}

	std::cout << bfs();
}
posted on 2023-04-14 08:38  Jack404  阅读(17)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3