zoukankan      html  css  js  c++  java
  • 机器人搬重物(BFS)

    原题:

    机器人搬重物

    时间限制: 1 Sec  内存限制: 256 MB

    题目描述

    机器人移动学会(RMI)现在正尝试用机器人搬运物品。机器人的形状是一个直径 1.6 米的球。在试验阶段,机器人被用于在一个储藏室中搬运货物。储藏室是一个 N×M 的网格,有些格子为不可移动的障碍。机器人的中心总是在格点上,当然,机器人必须在最短的时间内把物品搬运到指定的地方。机器人接受的指令有:向前移动 1 步(Creep);向前移动 2 步(Walk);向前移动 3 步(Run);向左转(Left);向右转(Right)。每个指令所需要的时间为 1 秒。请你计算一下机器人完成任务所需的最少时间。

     

    输入格式

    第一行为两个正整数 N,M (N,M ≤ 50),下面 N 行是储藏室的构造,0 表示无障碍,1 表示有障碍,数字之间用一个空格隔开。接着一行有 4 个整数和 1 个大写字母,分别为起始点和目标点左上角网格的行与列,起始时的面对方向(东 E,南 S,西 W,北 N),数与数,数与字母之间均用一个空格隔开。终点的面向方向是任意的。

    输出格式

    一个整数,表示机器人完成任务所需的最少时间。如果无法到达,输出 −1。

    输入输出样例

    输入 

    9 10
    0 0 0 0 0 0 1 0 0 0
    0 0 0 0 0 0 0 0 1 0
    0 0 0 1 0 0 0 0 0 0
    0 0 1 0 0 0 0 0 0 0
    0 0 0 0 0 0 1 0 0 0
    0 0 0 0 0 1 0 0 0 0
    0 0 0 1 1 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0
    1 0 0 0 0 0 0 0 1 0
    7 2 2 7 S

    输出 
    12
     
     

     
    题意:
           一道裸的BFS(如果不会自行百度),但是细节方面要注意的点有点多。
           在N*M的网格中,一个占据四个格子的物体要从起点走到终点,中途不能碰到障碍物,支持前进1,2,3步或者左右转向,耗时都为一秒,求最短耗时。
     
    先贴代码(我知道你们是来看这个的)
    自认为码风很干净的代码:
      1 #include<stdio.h>
      2 #include<iostream>
      3 #include<queue>
      4 using namespace std;
      5 struct node{ int x,y,s,z; }now;
      6 int n,m,sx,sy,ex,ey,ans,state,g[55][55],mark[55][55][5];
      7 //sx,sy起点坐标(start) ,ex,ey终点坐标(end) 
      8 //state标记最开始方向,g储存地图,mark标记
      9 //mark的三个下标分别确定行,列,方向 
     10 int d[4]={1,-1,2,-2},d2[3]={1,2,3};
     11 //d用于转换方向,d2用于移动 
     12 char ch;
     13 queue<node> q;
     14 bool check(int x,int y)
     15 {
     16     if(x<1||x>=n||y<1||y>=m)  return 0;
     17     //判断是否出界 
     18     if(g[x][y]||g[x][y+1]||g[x+1][y]||g[x+1][y+1])  return 0;
     19     //判断所在地是否有障碍物 
     20 return 1;
     21 }
     22 void bfs(int x,int y,int state)
     23 {
     24     for(int i=1;i<=n;i++)
     25         for(int j=1;j<=m;j++)
     26             for(int k=0;k<5;k++)  mark[i][j][k]=0x7fffffff;
     27     //初始化为最大值,方便下面更新最小值 
     28     mark[x][y][state+2]=0,q.push({x,y,0,state});
     29     while(!q.empty())
     30     {
     31         now=q.front();  q.pop();//取出队首 
     32         int x=now.x,y=now.y,s=now.s,z=now.z;
     33         for(int i=0;i<4;i++)
     34         {//依次判断四个方向移动是否可行 
     35             int tz,flag=0;
     36             if(d[i]==z)  tz=z,flag=1;
     37             else  if(d[i]+z)  tz=d[i];
     38             else  tz=d[i],flag=-1;
     39             //flag判断转换方向的特殊情况,1表示不动(0s),-1表示向后转(2s) 
     40             for(int j=1;j<=3;j++)
     41             {
     42                 int k,tx=x,ty=y,ts=s+2;//一般转向+移动共需2s 
     43                 if(flag==1)  ts--;//不转向共需1s 
     44                 else  if(flag==-1)  ts++;//不转向共需2s 
     45                 if(tz==2)//
     46                 {
     47                     for(k=1;k<=j;k++)
     48                     {
     49                         ty++;
     50                         if(!check(tx,ty))  break;
     51                         //移动过程中每一格都需要判断 
     52                     }
     53                     if(k<=j)  continue;//如果中途退出过表示不能移动 
     54                 }//以下代码复制略作修改即可 
     55                 else  if(tz==-2)//西 
     56                 {
     57                     for(k=1;k<=j;k++)
     58                     {
     59                         ty--;
     60                         if(!check(tx,ty))  break;
     61                     }
     62                     if(k<=j)  continue;
     63                 }
     64                 else  if(tz==1)//
     65                 {
     66                     for(k=1;k<=j;k++)
     67                     {
     68                         tx++;
     69                         if(!check(tx,ty))  break;
     70                     }
     71                     if(k<=j)  continue;
     72                 }
     73                 else  if(tz==-1)//
     74                 {
     75                     for(k=1;k<=j;k++)
     76                     {
     77                         tx--;
     78                         if(!check(tx,ty))  break;
     79                     }
     80                     if(k<=j)  continue;
     81                 }
     82                 if(mark[tx][ty][tz+2]>ts)
     83                 {
     84                     q.push({tx,ty,ts,tz});
     85                     mark[tx][ty][tz+2]=ts;
     86                 }
     87             }
     88         }
     89     }
     90 return;
     91 }
     92 int main()
     93 {
     94     scanf("%d %d",&n,&m);
     95     for(int i=1;i<=n;i++)
     96         for(int j=1;j<=m;j++)  scanf("%d",&g[i][j]);
     97     scanf("%d %d %d %d %c",&sx,&sy,&ex,&ey,&ch);
     98     switch(ch)
     99     {
    100         case 'S':state=1;break;
    101         case 'E':state=2;break;
    102         case 'N':state=-1;break;
    103         case 'W':state=-2;break;
    104     }//东西南北四个方向 
    105     bfs(sx,sy,state);
    106     int A=min(mark[ex][ey][0],mark[ex][ey][1]);
    107     int B=min(mark[ex][ey][3],mark[ex][ey][4]);
    108     ans=min(A,B);//寻找在终点时的最小步数 
    109     if(ans!=0x7fffffff)  printf("%d
    ",ans);
    110     else  printf("-1
    ");//若没有被更新过代表无解 
    111 return 0;
    112 }

    分块解析:

           BFS基本思路:把所有可行的、未标记过的点依次入队(当然了首先入队的是起点),依次取出后按所有可能性拓展,若没有可以再拓展的点代表搜索完毕。

           注意点1:一个机器人占据四个格子,所以代码中都使用左上角的坐标来储存。

           注意点2:题目中描述的允许操作是

    ①向前移动 1 步(Creep

    ②向前移动 2 步(Walk

    ③向前移动 3 步(Run

    向左转(Left

    向右转(Right

           在这里,允许的操作是左右旋转,所以我们需要宏观的东南西北来判断机器人的旋转方向。

           不妨使用2,-2,1,-1分别代表东、西、南、北,只要依次让机器人尝试这些方向,如果当前尝试的方向与原来的朝向的和为0,代表向后转;同样的如果相同即没有旋转,其他情况都为向左或右旋转。

           旋转了就必须移动(这不是废话嘛......不然你转他干什么),所以可以将旋转与移动合并为一次操作计时。

           注意在mark数组记录的时候要记录2个数据:坐标以及朝向。只有在同一地点、同一种朝向的情况下,如果当前方案比之前mark标记的最优方案更优才能更新。

           注意点3:判断目前搜索到的点是否可行,代码如下

    bool check(int x,int y)
    {
        if(x<1||x>=n||y<1||y>=m)  return 0;
        if(g[x][y]||g[x][y+1]||g[x+1][y]||g[x+1][y+1])  return 0;
    return 1;
    } 

           要注意一个点!机器人不管是爬还是走还是跑,过去的途中也不可以碰到障碍物!

           例如样例中的这个图,机器人(左上角)从网格第四行第一列直接向北跑三格到第一行第一列,若只判断左上角的目标地点是否可行的话,是可以移动的,但实际上这条路线是不被允许的,因为移动过程中会被障碍物挡住(毕竟机器人不是飞过去的),我就是因为这个WA了三次QAQ。所以我的做法是移动过程中碰到的的点依次判断是否可行。具体实现过程见代码第45行至81行。

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    Haskell Interactive Development in Emacs
    Access Java API in Groovy Script
    手工设置Eclipse文本编辑器的配色
    Color Theme of Emacs
    Gnucash的投资记录
    Special Forms and Syntax Sugars in Clojure
    Use w3m as Web Browser
    SSE指令集加速之 I420转BGR24
    【图像处理】 增加程序速度的方法
    TBB 入门笔记
  • 原文地址:https://www.cnblogs.com/leaf-2234/p/13861249.html
Copyright © 2011-2022 走看看