zoukankan      html  css  js  c++  java
  • P1979 华容道

    题意:$n*m$棋盘上$n*m-1$颗棋子,有且只有一个格子为空白格子,每个棋子大小$1*1$

       有些棋子可以移动,而有些棋子固定,任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。

       游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。

       现给定棋盘,q个询问,每次给出起始点,目标点,白块的位置,问最少步数,如果到不了输出-1

    输入输出样例

    输入样例#1: 
    3 4 2
    0 1 1 1
    0 1 1 0
    0 1 0 0
    3 2 1 2 2 2
    1 2 2 2 3 2
    输出样例#1: 
    2
    -1
    

    【输入输出样例说明】

    棋盘上划叉的格子是固定的,红色格子是目标位置,圆圈表示棋子,其中绿色圆圈表示目标棋子。

    1. 第一次游戏,空白格子的初始位置是(3,2)(图中空白所示),游戏的目标是将初始位置在(1,2)上的棋子(图中绿色圆圈所代表的棋子)移动到目标位置(2,2)(图中红色的格子)上。

    移动过程如下:

    1. 第二次游戏,空白格子的初始位置是(1,2)(图中空白所示),游戏的目标是将初始位置在(2,2)上的棋子(图中绿色圆圈所示)移动到目标位置 (3,2)上。

    要将指定块移入目标位置,必须先将空白块移入目标位置,空白块要移动到目标位置,必然是从位置(2,2)上与当前图中目标位置上的棋子交换位置,之后能与空白块交换位置的只有当前图中目标位置上的那个棋子,因此目标棋子永远无法走到它的目标位置, 游戏无法完成。

    看完题:果断-----爆搜啊

          20分。。。。。。TLE  QAQ(不过貌似可以70分)

    正解:

      脑补一下起始棋子移动的画面,起始棋子向终点移动一步,当且仅当空白格子与它相邻且在目标方向上

      所以,我们设dis[i][j][k][l][m]表示以i,j为起点,不经过与i,j相邻的m方向上的那个棋子,到各个点的最短路,

      考虑一下,白块与起始块交换后,起始块移动了一步,然后白块在起始块原来的位置上,

      要想让起始块再向目标前进一步,白块必须在与它相邻且在它目标方向的位置上,再与它交换才行,

      而dis数组恰好做到了这一点,找到白块不经过起始块到达起始块目标方向的块的最短路,直接统计,

      那一段有居多分支的搜索,我们直接省去了,节省了大量时间

      于是,相当于白块带着起始块满图瞎jb乱跑,跑到终点就行了QAQ

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cctype>
    #include<queue>
    #include<algorithm>
    using namespace std;
    #define int long long
    #define olinr return
    #define _ 0
    #define love_nmr 0
    #define DB double
    int rx[5]={0,0,0,1,-1};    //四个方向
    int ry[5]={0,1,-1,0,0};
    int dis[35][35][35][35][5];  //dis[i][j][k][l][m]代表从(i,j)到(k,l)不经过(i,j)m边的那一个格子的最短路(m=上,下,左,右)   
    bool mp[35][35];   //地图
    bool viss[35][35];    //spfa的vis
    bool cop[35][35];    //复制地图
    int n;
    int m;
    int q;
    int a,b,c,d,e,f;    //空白格子x,y    起始点x,y    终点x,y
    int ans;                //答案
    struct node    
    {
        int x;
        int y;
        int dis;
    };
    struct wmy
    {
        int dir;
        int x;
        int y;
        int dis;
    }lv[55];
    queue<node> que;
    int cnt;
    inline int read()
    {
        int x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch))
        {
            if(ch=='-')
                f=-f;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*f;
    }
    inline void put(int x)
    {
        if(x<0)
        {
            x=-x;
            putchar('-');
        }
        if(x>9)
            put(x/10);
        putchar(x%10+'0');
    }
    inline void spfa(int x,int y,int k)
    {
        while(!que.empty()) que.pop();
        dis[x][y][x][y][k]=0;
        que.push((node){x,y,0});
        while(!que.empty())
        {
            node tp=que.front();
            que.pop();
            viss[tp.x][tp.y]=false;
            for(int i=1;i<=4;i++)
            {
                int xx=tp.x+rx[i];
                int yy=tp.y+ry[i];
                if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&mp[xx][yy]&&dis[x][y][xx][yy][k]>dis[x][y][tp.x][tp.y][k]+1)
                {
                    dis[x][y][xx][yy][k]=dis[x][y][tp.x][tp.y][k]+1;
                    if(!viss[xx][yy])
                    {
                        viss[xx][yy]=true;
                        que.push((node){xx,yy,0});
                    }
                }
            }
        }
    }
    inline void bfs()
    {
        while(!que.empty()) que.pop();
        que.push((node){a,b,0});
        cop[a][b]=0;
        while(!que.empty())
        {
            node tp=que.front();
            que.pop();
            for(int i=1;i<=4;i++)
            {
                int xx=tp.x+rx[i];
                int yy=tp.y+ry[i];
                if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&cop[xx][yy])
                {
                    if(xx==c&&yy==d)
                    {
                        cnt++;   //记录白块到起始块的信息
                        lv[cnt].x=tp.x;
                        lv[cnt].y=tp.y;
                        lv[cnt].dis=tp.dis;
                        lv[cnt].dir=i;
                    }
                    else
                    {
                        cop[xx][yy]=0;
                        que.push((node){xx,yy,tp.dis+1});
                    }
                }
            }
        }
    }
    inline void dfs(int x,int y,int lst1,int lst2,int dir,int tot)
    {
        if(tot>=ans) return;
        if(x==e&&y==f)   //找到终点
        {
            ans=tot;
            return;
        }
        mp[x][y]=0;   //记为起始块已走过
        for(int i=1;i<=4;i++)
        {
            int xx=x+rx[i];
            int yy=y+ry[i];
            if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&mp[xx][yy]&&dis[lst1][lst2][xx][yy][dir]<=1e5)
                dfs(xx,yy,x,y,i,tot+dis[lst1][lst2][xx][yy][dir]+1);   //起始块向目标方向移动距离=白块从原来到现在的距离+1
        }
        mp[x][y]=1;  //回溯
     
    }
    signed main()
    {
        n=read();
        m=read();
        q=read();
        memset(dis,1,sizeof dis);     //五位数组,赋值1已经很大了
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                mp[i][j]=read();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                if(mp[i][j])
                    for(int k=1;k<=4;k++)     //跑spfa,处理不经过m方向的点的最短路(方法:把那个点变成无法走)
                    {
                        int xx=i+rx[k];
                        int yy=j+ry[k];
                        if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&mp[xx][yy])
                        {
                            mp[xx][yy]=0;
                            spfa(i,j,k);
                            mp[xx][yy]=1;
                        }
                    }
        while(q--)
        {
            cnt=0;
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                    cop[i][j]=mp[i][j];   //复制一遍进行操作
            a=read();
            b=read();
            c=read();
            d=read();
            e=read();
            f=read();
            if(c==e&&d==f)   //起点=终点
            {
                put(0);
                putchar('
    ');
                continue;
            }
            bfs();   //找到初始时空白块到起始块的距离
            if(!cnt)   //空白块连起始块都到不了QAQ
            {   
                put(-1);
                putchar('
    ');
                continue;
            }
            ans=0x7ffffffff;  //步数初始极大值
            for(int i=1;i<=cnt;i++)
                dfs(c,d,lv[i].x,lv[i].y,lv[i].dir,lv[i].dis);  //模拟跑路过程
            put(ans==0x7ffffffff? -1:ans);
            putchar('
    ');
        }
        olinr ~~(0^_^0)+love_nmr;
    }
     
  • 相关阅读:
    manacher算法笔记
    2019qbxtCSP-S2 模拟题1
    三元环计数
    踩坑日记
    我的Ubuntu16.04 安装配置
    SLAM14讲项目在 mac 上无法正常运行
    平面最近点对的算法实现
    hiho 1996
    【游记】NOIP2018 退役滚粗记
    铁板铮铮♂+习题集
  • 原文地址:https://www.cnblogs.com/olinr/p/9552077.html
Copyright © 2011-2022 走看看