题解:P10493 Bloxorz II
_Warfarin_ · · 题解
思路分析
上来我们一眼丁真为搜索,但再仔细一看数据范围
显然,这需要我们来找找规律,既然求的是最小步数,我们就要思考,如何走效果最好,不难发现只有横着横向滚动和竖着竖向滚动时,两步就能走三格,这是最快的。
因此我们可以发现,图中某些坐标
假设这些状态叫做合适点,那么我们只要让起点状态用最小步数走到合适点上,那么从起点到终点的距离就可以相加得出。所以,我们只用考虑起点周围的最近的合适点,这只需要我们将起点映射到一个
注意事项
建议在映射时,矩阵开大一些,避免数组越界。
AC 代码
#include <bits/stdc++.h>
#define ll long long
#define io cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define ri register int
#define lb long double
using namespace std;
const int N = 15;
typedef pair<int, int> qwq;
struct node
{
int x, y, direction;
};
char op[2];
// 初始状态
int _x, _y;
//起点横纵坐标
int d[N][N][3];
//横坐标
//纵坐标
//方向
int next_x[3][4] = {{-2, 1, 0, 0}, {-1, 1, 0, 0}, {-1, 2, 0, 0}};
//下步横坐标变化
int next_y[3][4] = {{0, 0, -2, 1}, {0, 0, -1, 2}, {0, 0, -1, 1}};
//下步纵坐标变化
int next_direction[3][4] = {{2, 2, 1, 1}, {1, 1, 0, 0}, {0, 0, 2, 2}};
//下步方向变化
inline int bfs(int x, int y, int direction)
{
memset(d, -1, sizeof d);
d[x][y][direction] = 0;
queue<node> q;
q.push({x, y, direction});
int ans = 1e10;
while (q.size())
{
auto t = q.front();
q.pop();
int x = t.x, y = t.y, z = t.direction;
if (x % 3 == 0 && y % 3 == 0 && z == 0)
{
int nx = _x + x - 3, ny = _y + y - 3;
int xd = nx / 3 * 2, yd = ny / 3 * 2;
//还原回去
if (xd < 0 || yd < 0)
continue;
//负数,说明非法,直接跳过
ans = min(ans, d[x][y][z] + xd + yd);
//更新合法答案
}
for (ri i = 0; i < 4; i++)
{
int a = x + next_x[z][i];
int b = y + next_y[z][i];
int _direction = next_direction[z][i];
if (a < 0 || a >= N || b < 0 || b >= N)
continue;
if (d[a][b][_direction] == -1)
{
d[a][b][_direction] = d[x][y][z] + 1;
q.push({a, b, _direction});
}
}
}
return ans;
}
int main()
{
io;
while (cin >> op >> _x >> _y && op[0] != EOF)
{
int z;
if (op[0] == 'U')
z = 0;
else if (op[0] == 'H')
z = 1;
else
z = 2;
int sx = _x % 3 + 3;
int sy = _y % 3 + 3;
cout << bfs(sx, sy, z) << endl;
}
return 0;
}