[NOIP 2013] 华容道
[题目链接]
[算法]
首先 , 有一个很显然的性质 : 无论空格怎样移动 , 地图都不会发生改变 , 我们关心的只有空格的位置和指定棋子的位置 , 通过这个性质 , 进行广度优先搜索BFS可以拿到80分
那么 , 怎样拿到满分呢?
首先 , 在开始时 , 我们一定会让空格移动至指定棋子的上下左右四个方向之一 , 当空格在指定棋子的四方向之一时 , 我们可以选择 :
1. 移动到指定棋子的另外一个方向( 不经过指定棋子 )
2. 与指定棋子交换位置
那么 , 不妨首先BFS预处理每个点到其他点的距离 , 然后建一张图 , 其中(120 * x + 4 * y + k)号节点表示指定棋子坐标为(x,y)空格在其k方向( 上 / 下 / 左 / 右 )
每次询问用单源最短路求出起始状态到目标状态需要多少次交换即可 , 笔者使用的是SPFA算法
时间复杂度 : O(N ^ 4)
[代码]
#include<bits/stdc++.h> using namespace std; #define MAXN 35 const int inf = 1e9; const int dx[4] = {-1,1,0,0}; const int dy[4] = {0,0,-1,1}; struct edge { int to,w,nxt; } e[MAXN * MAXN * MAXN * MAXN]; int n,m,q,tot; int head[MAXN * MAXN * MAXN]; int a[MAXN][MAXN]; int step[MAXN][MAXN],dist[MAXN * MAXN * MAXN]; struct info { int ex,ey,sx,sy; } ; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) { if (c == '-') f = -f; } for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline bool valid(int x,int y) { return x >= 1 && x <= n && y >= 1 && y <= m; } inline void addedge(int u,int v,int w) { tot++; e[tot] = (edge){v,w,head[u]}; head[u] = tot; } inline void bfs(int sx,int sy,int nx,int ny,int type) { int l,r; static pair<int,int> q[MAXN * MAXN]; memset(step,0,sizeof(step)); step[sx][sy] = 1; q[l = r = 1] = make_pair(sx,sy); while (l <= r) { pair<int,int> cur = q[l++]; for (int i = 0; i < 4; i++) { int x = cur.first + dx[i] , y = cur.second + dy[i]; if (valid(x,y) && a[x][y] == 1 && !step[x][y] && (x != nx || y != ny)) { step[x][y] = step[cur.first][cur.second] + 1; q[++r] = make_pair(x,y); } } } if (type == 4) return; for (int i = 0; i < 4; i++) { int x = nx + dx[i] , y = ny + dy[i]; if (valid(x,y) && (x != sx || y != sy) && step[x][y] > 0) addedge(nx * 120 + 4 * ny + type,nx * 120 + ny * 4 + i,step[x][y] - 1); } addedge(nx * 120 + 4 * ny + type,sx * 120 + sy * 4 + type ^ 1,1); } inline void spfa(int sx,int sy) { int l = 1,r = 0; static int q[MAXN * MAXN * MAXN]; static bool inq[MAXN * MAXN * MAXN]; for (int i = 0; i <= 120 * n + 4 * m + 3; i++) { dist[i] = inf; inq[i] = false; } for (int i = 0; i < 4; i++) { int x = sx + dx[i] , y = sy + dy[i]; if (step[x][y]) { inq[120 * sx + 4 * sy + i] = true; dist[120 * sx + 4 * sy + i] = step[x][y] - 1; q[++r] = 120 * sx + 4 * sy + i; } } while (l <= r) { int cur = q[l++]; inq[cur] = false; for (int i = head[cur]; i; i = e[i].nxt) { int v = e[i].to , w = e[i].w; if (dist[cur] + w < dist[v]) { dist[v] = dist[cur] + w; if (!inq[v]) { inq[v] = true; q[++r] = v; } } } } } int main() { read(n); read(m); read(q); for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { read(a[i][j]); } } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (!a[i][j]) continue; if (a[i - 1][j]) bfs(i - 1,j,i,j,0); if (a[i + 1][j]) bfs(i + 1,j,i,j,1); if (a[i][j - 1]) bfs(i,j - 1,i,j,2); if (a[i][j + 1]) bfs(i,j + 1,i,j,3); } } while (q--) { int ex,ey,sx,sy,tx,ty; read(ex); read(ey); read(sx); read(sy); read(tx); read(ty); if (sx == tx && sy == ty) { printf("0\n"); continue; } bfs(ex,ey,sx,sy,4); spfa(sx,sy); int ans = inf; for (int i = 0; i < 4; i++) chkmin(ans,dist[120 * tx + 4 * ty + i]); printf("%d\n",ans == inf ? -1 : ans); } return 0; }