P6233 [eJOI2019]Awesome Arrowland Adventure
比较容易的最短路。
主要考虑如何建图,可以发现每个点只要不是 X
,那么它可以和与它四联通的每个点建边,那么边权是多少呢?
设目前点为
那么如果一个点为 X
怎么办?有两种做法,一种是仍然建边,不过边权是
建完图后,可以发现,边权并不完全相同,考虑最短路或者 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
数组应该是二维,但是我的为什么是一维的呢?我们有一个办法,可以将坐标
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现