- 2013
T6
- @ 2025-10-4 17:11:04
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int, int> PII;
const int N = 35, M = 3610, K = 4 * M, INF = 0x3f3f3f3f;
//N是格子边长, M是状态个数, K是边的个数
int n, m, Q;
int h[M], e[K], ne[K], w[K], idx;
int dist1[N][N], dist2[M];
//dist1是网格bfs(箱子不动人动), dist2 spfa
int g[N][N];
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
bool st[M];
void add(int a, int b, int c)
{
e[idx] = b, ne[idx] = h[a], w[idx] = c;
h[a] = idx++;
}
int get(int i, int j, int k) //把状态变成点
{
return ((i - 1) * m + j - 1) * 4 + k;
}
void bfs(int px, int py, int bx, int by, int dir)
{
memset(dist1, 0x3f, sizeof dist1);
dist1[px][py] = dist1[bx][by] = 0;
queue<PII> q;
q.push({px, py});
while(q.size())
{
auto t = q.front();
q.pop();
for(int i = 0; i < 4; i++)
{
int x = t.x + dx[i], y = t.y + dy[i];
if(g[x][y] && dist1[x][y] > dist1[t.x][t.y] + 1)
{
dist1[x][y] = dist1[t.x][t.y] + 1;
q.push({x, y});
}
}
}
if(dir == -1) return; //只需要广搜 不需要建图
int id = get(bx, by, dir);
for(int i = 0; i < 4; i++)
{
if(i != dir) //如果需要加边
{
int x = bx + dx[i], y = by + dy[i];
if(dist1[x][y] < INF)
{
add(id, get(bx, by, i), dist1[x][y]);
}
}
}
add(id, get(px, py, dir ^ 2), 1);
}
int spfa(int sx, int sy, int tx, int ty)
{
queue<int> q;
memset(dist2, 0x3f, sizeof dist2);
for(int i = 0; i < 4; i++)
{
int x = sx + dx[i], y = sy + dy[i];
if(dist1[x][y] < INF)
{
int k = get(sx, sy, i);
dist2[k] = dist1[x][y];
q.push(k);
st[k] = 1;
}
}
while(q.size())
{
auto t = q.front();
q.pop();
st[t] = 0;
for(int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
if(dist2[j] > dist2[t] + w[i])
{
dist2[j] = dist2[t] + w[i];
if(!st[j])
{
q.push(j);
st[j] = 1;
}
}
}
}
int res = INF;
for(int i = 0; i < 4; i++)
res = min(res, dist2[get(tx, ty, i)]); //4个方向最短路是谁
if(res == INF) res = -1;
return res;
}
int main()
{
cin >> n >> m >> Q;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
cin >> g[i][j];
memset(h, -1, sizeof h);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++) //枚举箱子的位置(i, j)
if(g[i][j])
{
for(int k = 0; k < 4; k++)
{
int x = i + dx[k], y = j + dy[k];
if(g[x][y])
bfs(x, y, i, j, k);
}
}
while(Q --)
{
int ex, ey, sx, sy, tx, ty;
cin >> ex >> ey >> sx >> sy >> tx >> ty;
if(sx == tx && sy == ty) cout << 0 << endl;
else
{
bfs(ex, ey, sx, sy, -1);
cout << spfa(sx, sy, tx, ty) << endl;
}
}
return 0;
}
/*
最后一步之前,将白格移动到s的邻格
任何一个格子a 从(i, j)移动到相邻的格子b,需要让白格先移动到b
之后交换a与白格。a下一步还是要继续往其他方向移动,所以白格
仍然需要移动到a的某个相邻格。
设置一个状态(i, j, k)表示格子s在(i, j), 白格在(i, j)的方向k处
其中k=0 1 2 3 表示四个方向
转移状态时:
1.白格与s进行交换,在状态(si, sj, k)与(ei, ej, k) 之间连一条边,边权为1。
2.白格移动到了一个与s相邻的位置(x',y'),
此时状态(si, sj, k) 与 状态(si, sj, i)之间连边,边权为dis[x'][y']
我们将状态作为点,花费作为边,建图.
spfa (tx, ty, 0 / 1 / 2/ 3) 到(sx, sy, 0/1/2/3)最短路
*/
0 条评论
目前还没有评论...