「NOIP2013」华容道
solution by XiangXunYi
题目描述
给你一张华容道,有障碍格,共
思路推导
step 1
先思考暴力,发现状态与当前格子和空格的位置有关系,同时问最少步数,故采用最短路,定义
时间复杂度
step 2
我们可以发现只动一个格子且只有当空格在其附近才能动,所以只有空格与该格子四联通时的状态是有意义的,所以可以将后两位的
step 3
对于一个格子和其附近空格,有两种情况:
- 交换空格与格子,即从
向 连边 - 改变空格的位置,即从
向 连边
对于第一种情况,显然边权为
明显一开始空格可能不在其四联通分量中,所以要将空格移过来,枚举空格相对位置,并限制不能走到
tips: 当
solution
定义
代码
文字不多,代码挺长,自己打调还是难,不是同学帮忙估计还要多
/*
address:https://www.becoder.com.cn/problem/9288 or https://www.luogu.com.cn/problem/P1979
AC 2024/11/27 15:26
*/
#include<bits/stdc++.h>
using namespace std;
const int dx[] = { 0,0,1,-1,0 }, dy[] = { 1,-1,0,0,0 };
const int N = 35, M = N * N << 2;
const int INF = 0x3f3f3f3f;
int n, m, Q;
int a[N][N];
struct edge {
int to, w;
};
vector<edge>G[M];
int dist[M];
bool vis[M];
struct node {
int u, dist;
bool operator < (const node& o)const { return dist > o.dist; }
};
priority_queue<node>qq;
inline void dijkstra(int s) {
fill(dist + 1, dist + (n * m << 2) + 1, INF);
fill(vis + 1, vis + (n * m << 2) + 1, false);
dist[s] = 0;
qq.push({ s,0 });
while (!qq.empty()) {
int u = qq.top().u;
qq.pop();
if (vis[u]) continue;
vis[u] = true;
for (auto e : G[u])
if (dist[e.to] > dist[u] + e.w) {
dist[e.to] = dist[u] + e.w;
qq.push({ e.to,dist[e.to] });
}
}
}
inline bool check(int x, int y) { return x > 0 && x <= n && y > 0 && y <= m && a[x][y] == 1; }
int cnt;
int dis[N][N];
pair<int, int> qqq[N * N];
inline void bfs(int s, int t, int nx, int ny) {
int l = 1, r = 1;
qqq[r++] = { s,t };
for (int i = 1;i <= n;i++)
for (int j = 1;j <= m;j++) dis[i][j] = 0x3f3f3f3f;
dis[s][t] = 0;
while (l < r) {
int x = qqq[l].first, y = qqq[l].second;
l++;
for (int i = 0;i < 4;i++) {
int kx = x + dx[i], ky = y + dy[i];
if (!check(kx, ky) || kx == nx && ky == ny || dis[kx][ky] != 0x3f3f3f3f) continue;
dis[kx][ky] = dis[x][y] + 1;
qqq[r++] = { kx,ky };
}
}
}
int f[N][N][4][N][N], id[N][N][4];
int main() {
scanf("%d%d%d", &n, &m, &Q);
for (int i = 1;i <= n;i++)
for (int j = 1;j <= m;j++) scanf("%d", &a[i][j]);
for (int i = 1;i <= n;i++)
for (int j = 1;j <= m;j++)
if (check(i, j))
for (int k = 0;k < 4;k++) {
int x = i + dx[k], y = j + dy[k];
if (check(x, y)) {
bfs(i, j, x, y);
for (int p = 1;p <= n;p++)
for (int q = 1;q <= m;q++)
f[i][j][k][p][q] = dis[p][q];
}
}
for (int i = 1;i <= n;i++)
for (int j = 1;j <= m;j++)
if (check(i, j))
for (int p = 0;p < 4;p++)
if (check(i + dx[p], j + dy[p]))
id[i][j][p] = ++cnt;
for (int i = 1;i <= n;i++)
for (int j = 1;j <= m;j++)
if (check(i, j))
for (int p = 0;p < 4;p++) {
if (check(i + dx[p], j + dy[p])) {
for (int q = 0;q < 4;q++)
if (p != q && check(i + dx[q], j + dy[q]))
G[id[i][j][p]].push_back({ id[i][j][q],f[i + dx[p]][j + dy[p]][p ^ 1][i + dx[q]][j + dy[q]] });
G[id[i][j][p]].push_back({ id[i + dx[p]][j + dy[p]][p ^ 1],1 });
}
}
while (Q--) {
int ex, ey, sx, sy, tx, ty;scanf("%d%d%d%d%d%d", &ex, &ey, &sx, &sy, &tx, &ty);
int ans = 0x3f3f3f3f;
for (int p = 0;p < 4;p++) {
if (!check(sx + dx[p], sy + dy[p])) continue;
int cur = (sx == tx && sy == ty) ? 0 : f[sx + dx[p]][sy + dy[p]][p ^ 1][ex][ey];
dijkstra(id[sx][sy][p]);
int mn = 0x3f3f3f3f;
for (int q = 0;q < 4;q++)
if (check(tx + dx[q], ty + dy[q])) mn = min(mn, dist[id[tx][ty][q]]);
cur += mn;
ans = min(ans, cur);
}
printf("%d\n", ans >= 0x3f3f3f3f ? -1 : ans);
}
return 0;
}
特别鸣谢 XiangXunYi 帮调。
分类:
图论 / 图 / 最短路
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!