• [P1979][NOIP2013] 华容道 (BFS建图+SPFA)


    题意:给出一张地图,分为可走和不可走,有 T次询问,每次给出 3对坐标,分别为空白格子,指定的可移动棋子,目标位置的初始坐标,求出将可移动棋子移动到目标位置的最小步数;

    解法:BFS建图+SPFA;

    1.BFS建图:

    1. 首先可以想到,只有空格在目标棋子的旁边,才可以使目标棋子移动;

    2. 进行一次移动后,空格要再次回到目标棋子旁边,才可以继续移动;

    3. 而在移回的过程中,不可以经过目标棋子(否则会改变目标棋子的位置),这时相当于目标棋子是不可移动的;

    4. 而对于同一个图,对于某个指定的棋子来讲,与它相邻的空格从某个方向移到某个方向之间要走的步数是一定的;

    5. 所以可以预处理出对于某个指定的棋子,其临近的空格在不同状态之间转移的步数:f[x][y][i][j],表示空格在目标棋子(x,y)的 i 方向上,当目标棋子与空白格交换后,空白格重新移动到目标棋子的新位置(x+dx[i],y+dy[i])的 j 方向上的临近格子的最小步数(这个预处理要算上开始时的空白格与目标棋子交换的步数,即 +1,下面会有注释)

    2.SPFA:我们已经预处理出了状态,那么在每一次询问时,先预求出空白格移动到目标棋子四周的最小步数,然后将此时的目标棋子的位置和方向作为初始状态(可能有多个),就可以开始求最短路了;

    附上代码:

    #include<iostream> 
    #include<cstring> 
    #include<string> 
    #include<algorithm> 
    #include<cstdio> 
    #include<queue> 
    #define pr pair<int ,int >
    using namespace std;
    const int N = 233333;
    const int inf = 0x3f3f3f3f;
    
    int n,m,q;
    int map[35][35],a[35][35],s[35][35][4][4];
    int ex,ey,sx,sy,tx,ty,ans;
    int dx[]={1,-1,0,0},dy[]={0,0,-1,1};
    struct node{
        int x,y,dir;
    }nd[N];
    int head[N],cnt,l,r;
    int vis[35][35][4],f[35][35][4];
    
    void bfs(int x,int y,int op){
    //op==1,表示是预处理 s数组 ;op==0,表示是在预处理开始时空白块移动到目标棋子四周的最小距离 
        queue<pr> q;
        memset(a,inf,sizeof(a));
        if(op) a[x][y]=1;
        else a[x][y]=0;
        q.push(pr(x,y));
        while(!q.empty()){
            int xx=q.front().first,yy=q.front().second;
            q.pop();
            for(int i=0;i<4;++i){
                int fx=xx+dx[i],fy=yy+dy[i];
                if(map[fx][fy]==0||fx<1||fx>n||fy<1||fy>m) continue;
                if(a[fx][fy]==inf) a[fx][fy]=a[xx][yy]+1,q.push(pr(fx,fy));
            }
        }
    }
    
    void deal(){
        memset(s,inf,sizeof(s));
        for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j){
            if(map[i][j]){
                for(int k=0;k<4;++k){
                    int x=i+dx[k],y=j+dy[k];
                    if(x<1||x>n||y<1||y>m) continue;
                    if(map[x][y]){
                        map[x][y]=0;
                        bfs(i,j,1);
                        map[x][y]=1;
                        for(int l=0;l<4;++l){
                            int fx=x+dx[l],fy=y+dy[l];
                            if(fx<1||fx>n||fy<1||fy>m) continue;
                            if(a[fx][fy]<inf) s[i][j][k][l]=a[fx][fy];
                        }
                    }
                }
            }
        }
    }
    
    void spfa(){
        while(l<=r){
            int x=nd[l].x,y=nd[l].y,d=nd[l].dir;//目标方块 
            int fx=x+dx[d],fy=y+dy[d];//空白方块 
            vis[x][y][d]=0;
            for(int i=0;i<4;++i){
                if(s[x][y][d][i]!=inf&&f[fx][fy][i]>f[x][y][d]+s[x][y][d][i]){
                    f[fx][fy][i]=f[x][y][d]+s[x][y][d][i];
                    if(!vis[fx][fy][i]){
                        vis[fx][fy][i]=1;
                        nd[++r].x=fx,nd[r].y=fy,nd[r].dir=i;
                    }
                }
            }
            l++;
        }
    }
    
    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",&map[i][j]);
        deal();
        while(q--){
            scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
            if(sx==tx&&sy==ty){ puts("0");continue; }
            map[sx][sy]=0;
            bfs(ex,ey,0);
            map[sx][sy]=1;
            l=1,r=0;
            memset(f,inf,sizeof(f));
            memset(vis,0,sizeof(vis));
            for(int i=0;i<4;++i){
                int fx=sx+dx[i],fy=sy+dy[i];
                if(fx<1||fx>n||fy<1||fy>m) continue;
                if(a[fx][fy]<inf){
                    nd[++r].x=sx;
                    nd[r].y=sy;
                    nd[r].dir=i;
                    f[sx][sy][i]=a[fx][fy];
                    vis[sx][sy][i]=1;
                }
            }
            spfa();
            ans=inf;
            for(int i=0;i<4;++i) ans=min(ans,f[tx][ty][i]);
            if(ans==inf) printf("-1
    ");
            else printf("%d
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    scrum立会报告+燃尽图(第三周第一次)
    scrum立会报告+燃尽图(第二周第七次)
    scrum立会报告+燃尽图(第二周第六次)
    scrum立会报告+燃尽图(第二周第五次)
    scrum立会报告+燃尽图(第二周第四次)
    006_for
    005_while
    003_if_else
    002_how to use getpass
    图像旋转
  • 原文地址:https://www.cnblogs.com/nnezgy/p/11737076.html
Copyright © 2020-2023  润新知