RT,调了近半天未过样例,求神仙救人。
注释很够,码风是vscode格式化的码风。
#include <bits/stdc++.h>
using namespace std;
const int MAX = 37;
int N, M, Q;
int num[MAX][MAX];
int dis[5][2] = {0, 0, 1, 0, -1, 0, 0, -1, 0, 1};
//方向
/*前向星组件*/
struct edge
{
int next, to;
int val;
} e[100007 << 1];
int head[100007], eid = 1;
void adde(int x, int y, int w)
{
e[++eid].next = head[x];
e[eid].to = y;
e[eid].val = w;
head[x] = eid;
}
#define PII pair<int, int>
#define MP make_pair
int v[MAX][MAX];
struct statu //存状态
{
int x;
int y;
int dis;
statu(int a = 0, int b = 0, int c = 0)
{
x = a;
y = b;
dis = c;
}
};
/*get the dis from (x,y) to (xx,yy),can't pass (bx,by)*/
queue<statu> q;
int bfs(int x, int y, int xx, int yy, int bx, int by)
{
if (x == xx && y == yy)
{
return 0; //若起终相同则距离为0
}
while (q.size())
{
q.pop(); //清空
}
for (int i = 1; i <= 4; i++)
{
int xx = x + dis[i][0], yy = y + dis[i][1];
if (xx <= 0 || xx > N || yy <= 0 || yy > M || !num[xx][yy] || (xx == bx && yy == by))
{
continue;
}
q.push(statu(xx, yy, 1)); //将四个方向都入队
}
memset(v, 0, sizeof(v)); //v即vis,记录某点是否被访问
v[x][y] = 1;
while (!q.empty())
{
statu u = q.front();
q.pop();
if (u.x == xx && u.y == yy) //若走到目标则返回距离
{
return u.dis;
}
if (v[u.x][u.y])
{
continue;
}
v[u.x][u.y] = 1;
/*遍历四个方向,合法就入队*/
for (int i = 1; i <= 4; i++)
{
int nx = u.x + dis[i][0], ny = u.y + dis[i][1];
if (nx <= 0 || nx > N || ny <= 0 || ny > M || !num[nx][ny])
{
continue;
}
/*若该点是禁止被遍历的,就不走*/
if (bx == nx && by == ny)
{
continue;
}
q.push(statu(nx, ny, u.dis + 1));
}
}
return -1;
}
/*get id in matrix*/
int idx(int x, int y, int k) //获取编号
{
return ((x - 1) * M + y - 1) * 4 + k;
}
/*link around blocks*/
void link_around(int x, int y)
{
for (int i = 1; i <= 4; i++)
{
for (int j = i + 1; j <= 4; j++)
{
/*合法性判断*/
int xx = x + dis[i][0], yy = y + dis[i][1];
if (xx <= 0 || xx > N || yy <= 0 || yy > M || !num[xx][yy])
{
continue;
}
xx = x + dis[j][0], yy = y + dis[j][1];
if (xx <= 0 || xx > N || yy <= 0 || yy > M || !num[xx][yy])
{
continue;
}
/*从一个方向转移到另一个方向*/
int u = idx(x, y, i);
int v = idx(x, y, j);
int val = bfs(x + dis[i][0], y + dis[i][1], x + dis[j][0], y + dis[j][1], x, y);
if (val != -1)
{
adde(u, v, val);
adde(v, u, val);
}
}
}
}
/*link to another*/
void link_another(int x, int y) //交换空格和某位置
{
int xx = x + 1, yy = y;
if (xx <= 0 || xx > N || yy <= 0 || yy > M || !num[xx][yy])
{
;
}
else
{
int u = idx(x, y, 2);
int v = idx(xx, yy, 1); //上下
int dis = 1;
adde(u, v, dis);
adde(v, u, dis);
}
xx = x, yy = y + 1;
if (xx <= 0 || xx > N || yy <= 0 || yy > M || !num[xx][yy])
{
;
}
else
{
int u = idx(x, y, 4);
int v = idx(xx, yy, 3); //左右
int dis = 1;
adde(u, v, dis);
adde(v, u, dis);
}
}
/*build the whole graph*/
void build_graph()
{
for (int i = 1; i <= N; i++)
{
for (int j = 1; j <= M; j++)
{
if (num[i][j])
{
link_around(i, j);
link_another(i, j);
}
}
}
}
const int MAXN = 1e5 + 7;
/*dij*/
#define PII pair<int, int>
#define MP make_pair
#define GI greater<PII>
int root = 0;
priority_queue<PII, vector<PII>, GI> pq;
int dist[MAXN << 1];
int vis[MAXN << 1];
void dij()
{
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= N; i++)
{
dist[i] = 2147483647;
}
dist[root] = 0; //root是单源最短路的源
pq.push(MP(0, root));
while (!pq.empty())
{
PII tmp = pq.top();
pq.pop();
if (vis[tmp.second])
{
continue;
}
vis[tmp.second] = 1;
for (int j = head[tmp.second]; j; j = e[j].next)
{
int v = e[j].to, w = e[j].val;
if (dist[v] > dist[tmp.second] + w)
{
dist[v] = dist[tmp.second] + w;
pq.push(MP(dist[v], v));
}
}
}
}
int main()
{
cin >> N >> M >> Q;
for (int i = 1; i <= N; i++)
{
for (int j = 1; j <= M; j++)
{
cin >> num[i][j];
}
}
build_graph();
while (Q--)
{
int ex, ey, sx, sy, tx, ty;
cin >> ex >> ey >> sx >> sy >> tx >> ty;
int ans = 1e9 + 7;
/*特判起终同位、起终点不合法等情况*/
if (sx == tx && sy == ty)
{
cout << 0 << endl;
continue;
}
if (!num[sx][sy] || !num[tx][ty])
{
cout << -1 << endl;
continue;
}
for (int i = 1; i <= 4; i++)
{
int xx = sx + dis[i][0], yy = sy + dis[i][1];
if (xx <= 0 || xx > N || yy <= 0 || yy > M || !num[xx][yy])
{
continue;
}
int tmp = bfs(ex, ey, xx, yy, sx, sy);
//先把空格移到起始位置周围
if (tmp != -1)
{
root = idx(sx, sy, i);
dij();
for (int j = 1; j <= 4; j++)
{
ans = min(ans, tmp + dist[idx(tx, ty, i)]);
//取终点周围的空格位置中的最小值
}
}
}
if (ans == 1e9 + 7)
{
cout << -1 << endl;
continue;
}
cout << ans << endl;
}
}
/*
solve:
1.用bfs求出每个点的某个方向,到另一个方向的距离
2.将这一方向的状态与另一方向的状态之间连边,权值为距离
3.将上、下、左、右交换的状态连边
(以上状态都需合法)
4.特判起终重合、起终在非法点情况
5.对于每次询问,先用bfs把空格移到起点周围,将起点周围的情况入队
6.跑最短路
7.回答询问
图上状态表示起始点在x,y,空格在k方向
*/
好人一生平安。