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行。

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    Business Objects 基础
    常用的bw基础知识
    SAP BW传输请求操作步骤
    FI/CO 财务基础知识
    SAP财务常用数据源概览
    HANA 和 SAP NetWeaver BW
    Request.QueryString中文乱码
    完全备份类型
    SQL Server备份属于I/O密集型操作
    SQL Server 通过发布订阅 实现数据库同步
  • 原文地址:https://www.cnblogs.com/leaf-2234/p/13861249.html
Copyright © 2011-2022 走看看