P6233 [eJOI2019]Awesome Arrowland Adventure

比较容易的最短路。

主要考虑如何建图,可以发现每个点只要不是 X,那么它可以和与它四联通的每个点建边,那么边权是多少呢?

设目前点为 (x1,y1)(x_1, y_1),目标点为 (x2,y2)(x_2, y_2)(x2,y2)(x_2, y_2) 是与 (x1,y1)(x_1, y_1) 四联通的一个点,那么可得边权应该是目前点到目标点需要旋转的次数。

那么如果一个点为 X 怎么办?有两种做法,一种是仍然建边,不过边权是 \infty ,另一种是不建边,这两种都可行,但第二种更优一些。

建完图后,可以发现,边权并不完全相同,考虑最短路或者 01-BFS,实测 01-BFS 快一些。

另外,网格图最短路建议选择 Dijkstra,SPFA 复杂度会很高。

Dijkstra 代码:

#include <iostream>
#include <cmath>
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;

constexpr int N(505), M(1e6 + 5);

int n, m;
char c[N][N];

int dx[] = { -1, 1, 0, 0 }; // 上下左右
int dy[] = { 0, 0, -1, 1 };

#define get(x) (x == 'W' ? 2 : (x == 'E' ? 3 : (x == 'N' ? 0 : 1)))

#define change(x) (x == 'W' ? 'N' : (x == 'E' ? 'S' : (x == 'N' ? 'E' : 'W')))

#define cg(x, y) ((x - 1) * m + y)

struct Edge
{
	int to, cost;
	Edge(int _to, int _cost): to(_to), cost(_cost){}
};

vector<Edge> G[M];
int dis[M];
bool f[M];

struct Node
{
	int place, dist;
	Node(int _p, int _d): place(_p), dist(_d){}
	bool operator<(const Node& g) const
	{
		return dist > g.dist;
	}
};

inline void dijkstra()
{
	memset(dis, 0x3f, sizeof dis);
	dis[1] = 0;
	priority_queue<Node> q;
	q.push(Node(1, 0));
	while (q.size())
	{
		int l = q.top().place;
		q.pop();
		if (f[l]) continue;
		f[l] = true;
		for (register int i(0), j(G[l].size()); i < j; ++i)
		{
			register int nx(G[l][i].to);
			if (dis[nx] > dis[l] + G[l][i].cost)
			{
				dis[nx] = dis[l] + G[l][i].cost;
				if (!f[nx]) q.push(Node(nx, dis[nx]));
			}
		}
	}
}

int main()
{
	scanf("%d%d", &n, &m);
	for (register int i(1); i <= n; ++i)
	{
		for (register int j(1); j <= m; ++j)
		{
			scanf(" %c", &c[i][j]);
			if (c[i][j] != 'X')
			{
				int p(get(c[i][j])), k(cg(i, j)), nx(i + dx[p]), ny(j + dy[p]);
				char h(c[i][j]);
				if (nx >= 1 and nx <= n and ny >= 1 and ny <= m)
				{
					G[k].push_back(Edge(cg(nx, ny), 0)); // 原始方向
				}
				for (register int bn(1); bn <= 3; ++bn)
				{
					h = change(h);
					p = get(h);
					nx = i + dx[p], ny = j + dy[p];
					if (nx >= 1 and nx <= n and ny >= 1 and ny <= m) G[k].push_back(Edge(cg(nx, ny), bn));
				}
			}
		}
	}
	dijkstra();
	printf("%d\n", dis[cg(n, m)] == dis[0] ? -1 : dis[cg(n, m)]);
	return 0;
}

01-BFS 代码:

#include <iostream>
#include <cmath>
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;

constexpr int N(505), M(1e6 + 5);

int n, m;
char c[N][N];

int dx[] = { -1, 1, 0, 0 }; // 上下左右
int dy[] = { 0, 0, -1, 1 };

#define get(x) (x == 'W' ? 2 : (x == 'E' ? 3 : (x == 'N' ? 0 : 1)))

#define change(x) (x == 'W' ? 'N' : (x == 'E' ? 'S' : (x == 'N' ? 'E' : 'W')))

#define cg(x, y) ((x - 1) * m + y)

struct Edge
{
	int to, cost;
	Edge(int _to, int _cost): to(_to), cost(_cost){}
};

vector<Edge> G[M];
int dis[M];

inline void bfs()
{
	memset(dis, 0x3f, sizeof dis);
	dis[1] = 0;
	deque<int> q;
	q.push_back(1);
	while (q.size())
	{
		int l = q.front();
		q.pop_front();
		for (register int i(0), j(G[l].size()); i < j; ++i)
		{
			register int nx(G[l][i].to);
			if (dis[nx] > dis[l] + G[l][i].cost)
			{
				dis[nx] = dis[l] + G[l][i].cost;
				if (G[l][i].cost == 0) q.push_front(nx);
				else q.push_back(nx);
			}
		}
	}
}

int main()
{
	scanf("%d%d", &n, &m);
	for (register int i(1); i <= n; ++i)
	{
		for (register int j(1); j <= m; ++j)
		{
			scanf(" %c", &c[i][j]);
			if (c[i][j] != 'X')
			{
				int p(get(c[i][j])), k(cg(i, j)), nx(i + dx[p]), ny(j + dy[p]);
				char h(c[i][j]);
				if (nx >= 1 and nx <= n and ny >= 1 and ny <= m)
				{
					G[k].push_back(Edge(cg(nx, ny), 0)); // 原始方向
				}
				for (register int bn(1); bn <= 3; ++bn)
				{
					h = change(h);
					p = get(h);
					nx = i + dx[p], ny = j + dy[p];
					if (nx >= 1 and nx <= n and ny >= 1 and ny <= m) G[k].push_back(Edge(cg(nx, ny), bn));
				}
			}
		}
	}
	bfs();
	printf("%d\n", dis[cg(n, m)] == dis[0] ? -1 : dis[cg(n, m)]);
	return 0;
}

最后说一个技巧,大家看代码可以发现,我的代码有一个 #define cg(x, y) ((x - 1) * m + y),这是什么意思呢?不知道大家发现没有,这道题是一个二维的平面,我们最短路上的 dis 数组应该是二维,但是我的为什么是一维的呢?我们有一个办法,可以将坐标 (x,y)(x, y) 转化为一个唯一的值,其实就是以这个点为右下角,以 (1,1)(1, 1) 为左上角的矩形包括的点的个数,显然这个值是唯一的。

posted @   HappyBobb  阅读(4)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示