华容道[NOIP2013]

时间限制:1 s   内存限制:128 MB

题解

      考场上完全是按照暴搜来做的,但是打得大概不是很优美,连暴搜的分数都没拿全。题解倒是给的非常详细,但是看了很多遍都不知道应该怎么实现。最后决定一个函数一个函数地堆,堆了好多节课才堆完。唯一可取的地方大概是没有参考标程,完全是自己实现的,调过之后很有成就感。所以说即使是很困难的事,也还是有办法做到的啊。

棋盘毕竟小,除了暴搜之外其他看起来暴力的方法还是可以尝试的。华容道游戏可以分成两部分,第一部分是空白格移动到起始格周围,第二部分是空白格给起始棋子铺路直到抵达目标格。把每一个棋子上方规定为0,左方为1,右方为2,下方为3。在执行第二部分时空白格始终在目标格周围,所以我们需要掌握的其实是空白格从每一个格子0到1、1到3、3到2一类绕圈的步数,而且这个最短距离不能经过围绕的那一点,这个过程相当于建图。棋盘是固定的,所以整个程序对第二部分只需要一次BFS,第一部分则需要对每一个数据BFS。拥有了这两个距离,我们就可以每次用一遍带方向转移的spfa求出到目标点的最短路,不可达则输出-1。spfa过程中有两种转移:一是把白格子与起始棋子交换位置,花费1;二是把白格子从当前棋子的一侧移到另一侧,花费第二部分预处理出的路径长。数据里有一个坑就是起始点和目标点重合,这样的数据还莫名多……要是在考场上多半会考虑到这种情况,但是自己练习就不会注意到,还是态度不一样时间不一样的问题,不会为了拿分考虑每一个细节。

自己打完这道题之后成就感很高,如果看了标程也多半是过了就过了没有什么感觉。我们常常花很多时间去做那些无关紧要,也并不能提升自己的事,为了逃避困难,为了当下的轻松。但是事情过去之后,还是自己走过的经历更能带来美好的回忆。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int sj=32;
struct point
{
      int x,y,dir,step;
}temp;
queue<point> q;
int n,m,ca,ex,ey,sx,sy,tx,ty,ans,tp,bx;
int dis[sj][sj][4],f[sj][sj][4][4],jg[4],st[sj][sj];
bool kd[sj][sj],r[sj][sj][4],jl[sj][sj];
void bfs1(int x,int y)
{
     if(kd[x-1][y]){
         memset(jl,0,sizeof(jl));
         temp.x=x-1,temp.y=y,temp.step=0;
         while(!q.empty()) q.pop();
         q.push(temp);
         jl[x-1][y]=jl[x][y]=1;
         while(!q.empty()){
            temp=q.front(),q.pop();
            if(temp.x==x+1&&temp.y==y)  f[x][y][0][3]=f[x][y][3][0]=temp.step;
            if(temp.x==x&&temp.y==y+1)  f[x][y][0][2]=f[x][y][2][0]=temp.step;
            if(temp.x==x&&temp.y==y-1)  f[x][y][0][1]=f[x][y][1][0]=temp.step;
            if(kd[temp.x+1][temp.y]&&!jl[temp.x+1][temp.y]){
               q.push((point){temp.x+1,temp.y,temp.dir,temp.step+1});
               jl[temp.x+1][temp.y]=1;
            }
            if(kd[temp.x-1][temp.y]&&!jl[temp.x-1][temp.y]){
               q.push((point){temp.x-1,temp.y,temp.dir,temp.step+1});
               jl[temp.x-1][temp.y]=1;
            }
            if(kd[temp.x][temp.y+1]&&!jl[temp.x][temp.y+1]){
               q.push((point){temp.x,temp.y+1,temp.dir,temp.step+1});
               jl[temp.x][temp.y+1]=1;
            }
            if(kd[temp.x][temp.y-1]&&!jl[temp.x][temp.y-1]){
               q.push((point){temp.x,temp.y-1,temp.dir,temp.step+1});
               jl[temp.x][temp.y-1]=1;
            }
         }
     }
     if(kd[x][y-1]){
         memset(jl,0,sizeof(jl));
         temp.x=x,temp.y=y-1,temp.step=0;
         while(!q.empty()) q.pop();
         q.push(temp);
         jl[x][y-1]=jl[x][y]=1;
         while(!q.empty()){
            temp=q.front(),q.pop();
            if(temp.x==x+1&&temp.y==y)  f[x][y][1][3]=f[x][y][3][1]=temp.step;
            if(temp.x==x&&temp.y==y+1)  f[x][y][1][2]=f[x][y][2][1]=temp.step;
            if(kd[temp.x+1][temp.y]&&!jl[temp.x+1][temp.y]){
               q.push((point){temp.x+1,temp.y,temp.dir,temp.step+1});
               jl[temp.x+1][temp.y]=1;
            }
            if(kd[temp.x-1][temp.y]&&!jl[temp.x-1][temp.y]){
               q.push((point){temp.x-1,temp.y,temp.dir,temp.step+1});
               jl[temp.x-1][temp.y]=1;
            }
            if(kd[temp.x][temp.y+1]&&!jl[temp.x][temp.y+1]){
               q.push((point){temp.x,temp.y+1,temp.dir,temp.step+1});
               jl[temp.x][temp.y+1]=1;
            }
            if(kd[temp.x][temp.y-1]&&!jl[temp.x][temp.y-1]){
               q.push((point){temp.x,temp.y-1,temp.dir,temp.step+1});
               jl[temp.x][temp.y-1]=1;
            }
         }
     }
     if(kd[x][y+1]){
         memset(jl,0,sizeof(jl));
         temp.x=x,temp.y=y+1,temp.step=0;
         while(!q.empty()) q.pop();
         q.push(temp);
         jl[x][y+1]=jl[x][y]=1;
         while(!q.empty()){
            temp=q.front(),q.pop();
            if(temp.x==x+1&&temp.y==y){
               f[x][y][2][3]=f[x][y][3][2]=temp.step;
               break;
            }
            if(kd[temp.x+1][temp.y]&&!jl[temp.x+1][temp.y]){
               q.push((point){temp.x+1,temp.y,temp.dir,temp.step+1});
               jl[temp.x+1][temp.y]=1;
            }
            if(kd[temp.x-1][temp.y]&&!jl[temp.x-1][temp.y]){
               q.push((point){temp.x-1,temp.y,temp.dir,temp.step+1});
               jl[temp.x-1][temp.y]=1;
            }
            if(kd[temp.x][temp.y+1]&&!jl[temp.x][temp.y+1]){
               q.push((point){temp.x,temp.y+1,temp.dir,temp.step+1});
               jl[temp.x][temp.y+1]=1;
            }
            if(kd[temp.x][temp.y-1]&&!jl[temp.x][temp.y-1]){
               q.push((point){temp.x,temp.y-1,temp.dir,temp.step+1});
               jl[temp.x][temp.y-1]=1;
            }
         }
     }
}
void bfs2()
{
     memset(st,0x3f,sizeof(st));
     bx=st[0][0];
     while(!q.empty()) q.pop();
     q.push((point){ex,ey,0,0});
     st[ex][ey]=0;
     kd[sx][sy]=0;
     while(!q.empty()){
        temp=q.front();
        if(st[temp.x][temp.y]<temp.step){
           q.pop();
           continue;
        }
        q.pop();
        if(kd[temp.x+1][temp.y]&&temp.step+1<st[temp.x+1][temp.y]){
           q.push((point){temp.x+1,temp.y,0,temp.step+1});
           st[temp.x+1][temp.y]=temp.step+1;
        }
        if(kd[temp.x-1][temp.y]&&temp.step+1<st[temp.x-1][temp.y]){
           q.push((point){temp.x-1,temp.y,0,temp.step+1});
           st[temp.x-1][temp.y]=temp.step+1;
        }
        if(kd[temp.x][temp.y+1]&&temp.step+1<st[temp.x][temp.y+1]){
           q.push((point){temp.x,temp.y+1,0,temp.step+1});
           st[temp.x][temp.y+1]=temp.step+1;
        }
        if(kd[temp.x][temp.y-1]&&temp.step+1<st[temp.x][temp.y-1]){
           q.push((point){temp.x,temp.y-1,0,temp.step+1});
           st[temp.x][temp.y-1]=temp.step+1;
        }
     }
     jg[0]=st[sx-1][sy];
     jg[1]=st[sx][sy-1];
     jg[2]=st[sx][sy+1];
     jg[3]=st[sx+1][sy];
     kd[sx][sy]=1;
}
void spfa()
{
     memset(dis,0x3f,sizeof(dis));
     tp=dis[0][0][0];
     for(int i=0;i<=3;i++)
      if(jg[i]!=bx)
        dis[sx][sy][i]=jg[i];
     while(!q.empty()) q.pop();
     for(int i=0;i<=3;i++)
       if(jg[i]!=bx)
        q.push((point){sx,sy,i,jg[i]}),r[sx][sy][i]=1;
     int nx,ny,ns,nd;
     while(!q.empty()){
        nx=q.front().x,ny=q.front().y,ns=dis[q.front().x][q.front().y][q.front().dir],nd=q.front().dir;
        q.pop(),r[nx][ny][nd]=0;
        if(nd==0){
          if(kd[nx-1][ny]&&dis[nx-1][ny][3]>ns+1){
            dis[nx-1][ny][3]=ns+1;
            if(!r[nx-1][ny][3])  q.push((point){nx-1,ny,3,ns+1});
          }
          if(dis[nx][ny][1]>ns+f[nx][ny][0][1]){
            dis[nx][ny][1]=ns+f[nx][ny][0][1];
            if(!r[nx][ny][1])   q.push((point){nx,ny,1,dis[nx][ny][1]});
          }
          if(dis[nx][ny][2]>ns+f[nx][ny][0][2]){
            dis[nx][ny][2]=ns+f[nx][ny][0][2];
            if(!r[nx][ny][2])   q.push((point){nx,ny,2,dis[nx][ny][2]});
          }
          if(dis[nx][ny][3]>ns+f[nx][ny][0][3]){
            dis[nx][ny][3]=ns+f[nx][ny][0][3];
            if(!r[nx][ny][3])   q.push((point){nx,ny,3,dis[nx][ny][3]});
          }
        }
        if(nd==1){
          if(kd[nx][ny-1]&&dis[nx][ny-1][2]>ns+1){
            dis[nx][ny-1][2]=ns+1;
            if(!r[nx][ny-1][2])  q.push((point){nx,ny-1,2,ns+1});
          }
          if(dis[nx][ny][0]>ns+f[nx][ny][1][0]){
            dis[nx][ny][0]=ns+f[nx][ny][1][0];
            if(!r[nx][ny][0])   q.push((point){nx,ny,0,dis[nx][ny][0]});
          }
          if(dis[nx][ny][2]>ns+f[nx][ny][1][2]){
            dis[nx][ny][2]=ns+f[nx][ny][1][2];
            if(!r[nx][ny][2])   q.push((point){nx,ny,2,dis[nx][ny][2]});
          }
          if(dis[nx][ny][3]>ns+f[nx][ny][1][3]){
            dis[nx][ny][3]=ns+f[nx][ny][1][3];
            if(!r[nx][ny][3])   q.push((point){nx,ny,3,dis[nx][ny][3]});
          }
        }
        if(nd==2){
          if(kd[nx][ny+1]&&dis[nx][ny+1][1]>ns+1){
            dis[nx][ny+1][1]=ns+1;
            if(!r[nx][ny+1][1])  q.push((point){nx,ny+1,1,ns+1});
          }
          if(dis[nx][ny][1]>ns+f[nx][ny][2][1]){
            dis[nx][ny][1]=ns+f[nx][ny][2][1];
            if(!r[nx][ny][1])   q.push((point){nx,ny,1,dis[nx][ny][1]});
          }
          if(dis[nx][ny][0]>ns+f[nx][ny][2][0]){
            dis[nx][ny][0]=ns+f[nx][ny][2][0];
            if(!r[nx][ny][0])   q.push((point){nx,ny,0,dis[nx][ny][0]});
          }
          if(dis[nx][ny][3]>ns+f[nx][ny][2][3]){
            dis[nx][ny][3]=ns+f[nx][ny][2][3];
            if(!r[nx][ny][3])   q.push((point){nx,ny,3,dis[nx][ny][3]});
          }
        }
        if(nd==3){
          if(kd[nx+1][ny]&&dis[nx+1][ny][0]>ns+1){
            dis[nx+1][ny][0]=ns+1;
            if(!r[nx+1][ny][0])  q.push((point){nx+1,ny,0,ns+1});
          }
          if(dis[nx][ny][1]>ns+f[nx][ny][3][1]){
            dis[nx][ny][1]=ns+f[nx][ny][3][1];
            if(!r[nx][ny][1])   q.push((point){nx,ny,1,dis[nx][ny][1]});
          }
          if(dis[nx][ny][2]>ns+f[nx][ny][3][2]){
            dis[nx][ny][2]=ns+f[nx][ny][3][2];
            if(!r[nx][ny][2])   q.push((point){nx,ny,2,dis[nx][ny][2]});
          }
          if(dis[nx][ny][0]>ns+f[nx][ny][3][0]){
            dis[nx][ny][0]=ns+f[nx][ny][3][0];
            if(!r[nx][ny][0])   q.push((point){nx,ny,0,dis[nx][ny][0]});
          }
        }
     }
     for(int i=0;i<=3;i++)
       if(ans>dis[tx][ty][i])
         ans=dis[tx][ty][i];
}
int main()
{
    scanf("%d%d%d",&n,&m,&ca);
    for(int i=1;i<=n;i++)
      for(int j=1;j<=m;j++)
        scanf("%d",&kd[i][j]);
    memset(f,0x3f,sizeof(f));
    for(int i=1;i<=n;i++)
      for(int j=1;j<=m;j++)
        if(kd[i][j])
          bfs1(i,j);
    for(int l=1;l<=ca;l++){
       scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
       if(tx==sx&&ty==sy){
          printf("0\n");
          continue;
       }
       bfs2();
       ans=0x7fffffff;
       spfa();
       if(ans==tp) printf("-1\n");
       else printf("%d\n",ans);
    }
    return 0;
}

puzzle

时间: 2024-10-01 05:27:42

华容道[NOIP2013]的相关文章

洛谷P1979 华容道 [NOIP2013]

题目描述 [问题描述] 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少需要多少时间. 小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的: 在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的: 有些棋子是固定的,有些棋子则是可以移动的: 任何与空白的格子相邻(有公共的边)的格子上

【NOIP2013】华容道

P1675 - [NOIP2013]华容道 Description Input Output Sample Input Sample Output Hint 暴力:BFS. 搜索空白的格子往四周走. 队列里面记录空格的位置和目标块的位置和步数,并且标记这个状态不能重复走. 这样搞好像有80分. 正解:BFS+SPFA. 要使某个块走到特定的点,首先要使空格移到这个块的边上. 然后再不断地移这个块. 所以,先要BFS求出空白块移到这个块需要多少步. 然后空白块就在这个块边上了. 考虑到要不停的移这

[RT][NOIP2013]华容道

1.题面 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间.小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的: 在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的: 有些棋子是固定的,有些棋子则是可以移动的: 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空

noip2013 华容道

P1979 华容道 131通过 471提交 题目提供者该用户不存在 标签图论搜索/枚举2013NOIp提高组 难度省选/NOI- 提交该题 讨论 题解记录 最新讨论 要注意部分数据存在起点与终… 求助求助求助 题目数据是不是有问题啊 题目描述 [问题描述] 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少需要多少时间. 小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的: 在一

NOIP2013 提高组day2 3 华容道 BFS

描述 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间. 小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的: 在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的: 有些棋子是固定的,有些棋子则是可以移动的: 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白

Luogu1979【NOIP2013】 华容道

题目描述 [问题描述] 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少需要多少时间. 小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的: 在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的: 有些棋子是固定的,有些棋子则是可以移动的: 任何与空白的格子相邻(有公共的边)的格子上

[noip2013][codevs3290]华容道 bfs+spfa

const u:array[1..4] of integer=(-1,0,1,0); v:array[1..4] of integer=(0,1,0,-1); oo=100000000; type node=record x,y,cs,l:longint; end; var ft:text; n,m,q,ii,i,i1,j1,j,l,w,x,y,x1,y1,x2,y2,x3,y3,es,ey,wei,tou,kx,ky,ans:longint; r:array[0..5000000] of no

[NOIP2013]华容道 又是爆搜

这道题我是真的虚啊..搜起来完全没思路 然后我就看了看网上的题解.都好简略,而且看不太明白. 再然后就看了看别人的代码. 因为我们移动目标旗子到指定位置,就相当于移动空格子.然后移动空格子到目标旗子的周围给它铺路.然后我们需要移动空格子到目标旗子需要到达的路径的方向上. 预处理出来每个点周围的点互相到达的距离,然后以移动步数为边权建图 最后每次询问的时候spfa跑一遍最短路即可 #include<cstdio> #include<cstring> #include<iostr

NOIP2013华容道——史上最强题解

[解题思路] 解题思路 这道题的数据范围是n≤30,所以,我们可以看到,裸的O(n4) 的宽搜对于求解q较小的情况是无压力的,但是在q大的情况下,毫无疑问会时间超限,明显,在q较大的情况下,我们需要将每次宽搜中重复搜索的冗余信息除去,所以我们可以先分析题目性质:(这里称要移动的棋子为目标棋子) 首先,如果要移动目标棋子,那么我们首先必须要将空格移到该棋子的上下左右四个方 向上相邻位置之一,然后才可以移动该棋子. 然后,我们分析该棋子移动时候的性质: 棋子每次可以移动,仅当空格位于其相邻位置的时候