[洛谷P1979]华容道:搜索+最短路

分析:

一个很显然的暴力是设dis[x][y][p][q]记录yyb和空格的坐标,每次bfs一遍。

可以发现,如果你想要移动点(x,y),那么空格一定要在(x,y)边上。对于yyb,显然你只关心她的位置和空格的位置。而空格总要在yyb边上才能发挥作用。

考虑预处理一下这个东西:f[i][j][p][q]表示在不动i,j的情况下,将空格从(i,j)的p方向移动到q方向至少需要多少步。然后,对于每次询问,设dis[x][y][p]表示yyb在(x,y),空格在她的p方向上。只有两种转移:1.yyb移动到空格上;2.空格移动到yyb的另一侧。因为预处理了f数组,我们可以快速计算出第二种转移的代价。于是,复杂度就变成了O((n*m)^2*16+q*最短路(n*m*4))。

需要注意的是,在一开始的时候,空格不一定在yyb边上。所以需要先bfs求出把空格移动到yyb身边各个方向分别需要多少时间,再跑多源最短路即可。

(我又犯懒了......)

代码:

(可能与分析不符,但思路是差不多的。)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <utility>
typedef std::pair<int,int> Pair;

int n,m,q,a[35][35],dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
int dis[35][35],dis2[4005],head[4005],ecnt;
bool vis[35][35],book[4005];
struct Edge{
    int to,nxt,w;
}e[5005];

inline void add_edge(int bg,int ed,int val){
    ecnt++;
    e[ecnt].to=ed;
    e[ecnt].nxt=head[bg];
    e[ecnt].w=val;
    head[bg]=ecnt;
}

std::queue<Pair> q1;
std::queue<int> q2;

inline void bfs(int sx,int sy,int tx,int ty,int typ){
    memset(vis,0,sizeof vis);
    while(!q1.empty()) q1.pop();
    dis[sx][sy]=0;
    vis[sx][sy]=1;
    q1.push((Pair){sx,sy});
    while(!q1.empty()){
        int x=q1.front().first,y=q1.front().second;q1.pop();
        for(int i=1;i<=4;i++){
            int xx=x+dx[i],yy=y+dy[i];
            if(!vis[xx][yy]&&!(xx==tx&&yy==ty)&&a[xx][yy]){
                dis[xx][yy]=dis[x][y]+1;
                vis[xx][yy]=1;
                q1.push((Pair){xx,yy});
            }
        }
    }
    if(typ==5) return;
    for(int i=1;i<=4;i++){
        int xx=tx+dx[i],yy=ty+dy[i];
        if(!vis[xx][yy]||(xx==sx&&yy==sy)) continue;
        add_edge(((tx-1)*31+ty)*4+typ-1,((tx-1)*31+ty)*4+i-1,dis[xx][yy]);
    }
    add_edge(((tx-1)*31+ty)*4+typ-1,((sx-1)*31+sy)*4+(typ%2==1?typ:typ-2),1);
}

inline void spfa(int sx,int sy){
    memset(dis2,0x3f,sizeof dis2);
    while(!q2.empty()) q2.pop();
    for(int i=1;i<=4;i++){
        int xx=sx+dx[i],yy=sy+dy[i];
        if(!vis[xx][yy]) continue;
        dis2[((sx-1)*31+sy)*4+i-1]=dis[xx][yy];
        q2.push(((sx-1)*31+sy)*4+i-1);
        book[((sx-1)*31+sy)*4+i-1]=1;
    }
    while(!q2.empty()){
        int u=q2.front();
        for(int i=head[u];i;i=e[i].nxt){
            int ver=e[i].to;
            if(dis2[ver]>dis2[u]+e[i].w){
                dis2[ver]=dis2[u]+e[i].w;
                if(!book[ver]){
                    q2.push(ver);
                    book[ver]=1;
                }
            }
        }
        q2.pop();
        book[u]=0;
    }
}

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(!a[i][j]) continue;
            if(a[i-1][j]) bfs(i-1,j,i,j,1);
            if(a[i+1][j]) bfs(i+1,j,i,j,2);
            if(a[i][j-1]) bfs(i,j-1,i,j,3);
            if(a[i][j+1]) bfs(i,j+1,i,j,4);
        }
    while(q--){
        int ex,ey,sx,sy,tx,ty;
        scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
        if(sx==tx&&sy==ty){
            printf("0\n");
            continue;
        }
        bfs(ex,ey,sx,sy,5);
        spfa(sx,sy);
        int ans=1e9;
        for(int i=1;i<=4;i++)
            ans=std::min(ans,dis2[((tx-1)*31+ty)*4+i-1]);
        if(ans==1e9) printf("-1\n");
        else printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ErkkiErkko/p/9702667.html