LP1979 NOIP2013 华容道

Author Avatar
空気浮遊 2018年10月29日
  • 在其它设备中阅读本文章

Problem

https://www.luogu.org/problemnew/show/P1979

Solution

朴素算法是 $O(qn^4)$ 的 BFS,能过约 80 分。

考虑若目标棋子需要移动,则空白格子一定与目标棋子相邻。

因此设计状态 $(x, y, g)$,表示空白棋子与目标棋子 $(x, y)$ 相邻的的方向。

预处理 $(x, y, g_1, g_2)$,代表状态 $(x, y, g_1)$ 到 $(x, y, g_2)$ 的最少步数。

查询时先 BFS 到达与目标棋子相邻的状态,再 SPFA 在该状态上最短路即可。

为什么用 SPFA?

因为当年 SPFA 还没死(逃

理论复杂度 $O(4n^4+qn^3)$

Code

// Code by ajcxsu
// Problem: chess road

#include<bits/stdc++.h>
#define CLR(x, y) memset(x, y, sizeof(x))
using namespace std;

const int N=31;
int mp[N][N];
int e[N][N][4][4];
int dist[N][N][4];
char S[N][N][4];

int mv[]={0, 1, 0, -1, 0};
int opp[]={2, 3, 0, 1};
int n, m;
bool valid(int x, int y) { return x>=1 && x<=n && y>=1 && y<=m && mp[x][y]; }
struct Dot { int x, y, g; } ;
queue<Dot> qu;
int dis[N][N];
void bfs(int x, int y, int g) {
    CLR(dis, 0x3f);
    if(!valid(x+mv[g], y+mv[g+1])) return;
    mp[x][y]=0;
    qu.push({x+mv[g], y+mv[g+1]});
    dis[x+mv[g]][y+mv[g+1]]=0;
    Dot na;
    int nx, ny;
    while(!qu.empty()) {
        na=qu.front(), qu.pop();
        for(int i=0;i<4;i++) {
            nx=na.x+mv[i], ny=na.y+mv[i+1];
            if(valid(nx, ny) && dis[nx][ny]>dis[na.x][na.y]+1) {
                dis[nx][ny]=dis[na.x][na.y]+1;
                qu.push({nx, ny});
            }
        }
    }
    for(int i=0;i<4;i++)
        e[x][y][g][i]=dis[x+mv[i]][y+mv[i+1]];
    mp[x][y]=1;
}

int SPFA(int sx, int sy, int ex, int ey, int tx, int ty) {
    if(ex==tx && ey==ty) return 0;
    CLR(dist, 0x3f);
    CLR(dis, 0x3f);
    mp[ex][ey]=0;
    qu.push({sx, sy});
    dis[sx][sy]=0;
    Dot na;
    int nx, ny, ng;
    while(!qu.empty()) {
        na=qu.front(), qu.pop();
        for(int i=0;i<4;i++) {
            nx=na.x+mv[i], ny=na.y+mv[i+1];
            if(valid(nx, ny) && dis[nx][ny]>dis[na.x][na.y]+1) {
                dis[nx][ny]=dis[na.x][na.y]+1;
                qu.push({nx, ny});
            }
        }
    }
    mp[ex][ey]=1;
    for(int i=0;i<4;i++) if(valid(ex+mv[i], ey+mv[i+1])) {
        dist[ex][ey][i]=dis[ex+mv[i]][ey+mv[i+1]], qu.push({ex, ey, i}),
        S[ex][ey][i]=1;
    }
    while(!qu.empty()) {
        na=qu.front(), qu.pop(); S[na.x][na.y][na.g]=0;
        for(int i=0;i<4;i++) {
            nx=na.x+mv[i], ny=na.y+mv[i+1], ng=opp[i];
            if(valid(nx, ny) && dist[nx][ny][ng]>dist[na.x][na.y][na.g]+e[na.x][na.y][na.g][i]+1) {
                dist[nx][ny][ng]=dist[na.x][na.y][na.g]+e[na.x][na.y][na.g][i]+1;
                if(!S[nx][ny][ng]) qu.push({nx, ny, ng});
            }
        }
    }
    int ans=0x3f3f3f3f;
    for(int i=0;i<4;i++) ans=min(ans, dist[tx][ty][i]);
    return ans;
}

int main() {
    CLR(e, 0x3f);
    ios::sync_with_stdio(false), cin.tie(0);
    int q;
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++) cin>>mp[i][j];
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++) if(mp[i][j])
        for(int k=0;k<4;k++) bfs(i, j, k);
    int a, b, c, d, e, f, res;
    while(q--) {
        cin>>a>>b>>c>>d>>e>>f;
        cout<<((res=SPFA(a, b, c, d, e, f))==0x3f3f3f3f?-1:res)<<endl;
    }
    return 0;
}