zoukankan      html  css  js  c++  java
  • 【bfs+优先队列】POJ2049-Finding Nemo

    基本上算是普通但略有些繁琐的广搜。给出的墙面和门的坐标为点,而Nemo位于方格中。

    【思路】

    首先思考一下如何存储下整个坐标系。我们预先约定,用一个方格的左下角顶点坐标来作为这个方格的坐标。map[i][j][k]数组是一个三维数组,下标前两位表示当前方格坐标为(i,j),第三位依次表示方格的上下左右,对应下标中的元素用0表示空白,1表示有墙,2表示有门。读入数据的时候,同时修改该墙或门两侧的方格。注意dx、dy数组一定要与上下左右的方向对应,方便后续操作。最后读入Nemo的坐标只要去尾法强制取整即可。但是看别人讨论,强制取整不能用(int),否则会WA,我试了一下的确会有这种问题。用floor会直接将float赋给int可以解决问题。

    广搜时从Nemo开始倒退,由于我们需要比较的是经过最小的门数,而不是走的最小步数,广搜的队列必须要用优先队列存储。

    【剪枝】

    当没有任何一道门或墙的时候,即m=n=0时,直接输出0;

    当Nemo在迷宫最大范围外,即fx>199||fy>199||fx<0||fy<0,直接输出0;

    读入数据时记录下门或墙纵坐标的最大最小值,最小值为起点减1,最大值为起点加上长度。当前坐标中某一位大于这个极值时,可以直接走到终点,直接输出此时的步数;

    (和上一步略有重复)当前坐标大于门或墙横纵坐标最大值时,只会越走越远,所以可以制止搜索继续。但不能把(nowx<0 || nowy<0 || nowx>limitx || nowy>limity) 写成(nowx<littlex || nowy<littley || nowx>limitx || nowy>limity),因为Nemo倒推时总是越来越趋向于(0,0)点,这么判断会使得大多数情形都变成无解。

      1 #include<queue>
      2 #include<iostream>
      3 #include<cstdio>
      4 #include<cstring>
      5 using namespace std;
      6 const int MAXN=205;
      7 const int INF=1000000;
      8 struct point
      9 {
     10     int x,y,num;
     11     bool operator < (const point &x) const
     12     {
     13         return num>x.num;
     14         /*优先队列设置为小顶堆*/
     15     }
     16 };
     17 int m,n;
     18 int limitx,limity,littlex,littley,fx,fy;
     19 int map[MAXN][MAXN][4];
     20 int step[MAXN][MAXN];
     21 /*方格的坐标用左下角顶点坐标来记录*/
     22 /*第三维依次代表上下左右*/ 
     23 /*数组内元素的值0:空白 1:墙 2:门*/
     24 int dx[4]={0,0,-1,1};
     25 int dy[4]={1,-1,0,0};
     26 /*d数组要对应上下左右的顺序,方便后续操作*/
     27 int vis[MAXN][MAXN];
     28 float initx,inity;
     29 
     30 void initwall()
     31 {
     32     memset(map,0,sizeof(map));
     33     limitx=limity=-1;
     34     littlex=littley=INF;
     35     int x,y,d,t;
     36     for (int i=0;i<m;i++)
     37     {
     38         cin>>x>>y>>d>>t;
     39         if (x+t>limitx) limitx=x+t;
     40         if (y+t>limity) limity=y+t;
     41         if (x-1<littlex) littlex=x-1;
     42         if (y-1<littley) littley=y-1;
     43         if (d==0)
     45         {
     46           for (int j=x;j<x+t;j++)
     47           {
     49               map[j][y][1]=1;
     50               if (y>=1) map[j][y-1][0]=1;
     51           }
     52         }
     53         else
     54         {
     56             for (int j=y;j<y+t;j++)
     57             {
     58                 map[x][j][2]=1;
     59                 if (x>=1) map[x-1][j][3]=1;
     60             }
     61         }
     62     }
     63 }
     64 
     65 void initdoor()
     66 {
     67     int x,y;
     68     int d;
     69     for (int i=0;i<n;i++)
     70     {
     71         scanf("%d%d%d",&x,&y,&d);
     72         if (x+1>limitx) limitx=x+1;
     73         if (y+1>limity) limity=y+1;
     74         if (x-1<littlex) littlex=x-1;
     75         if (y-1<littley) littley=y-1;
     76         if (d==0)
     77         {
     78                 map[x][y][1]=2;
     79                 if (y>=1) map[x][y-1][0]=2;
     80         }
     81         else
     82         {
     83                 map[x][y][2]=2;
     84                 if (x>=1) map[x-1][y][3]=2;
     85         }
     86     }
     87 }
     88 
     89 int bfs()
     90 {
     91     for (int i=0;i<=limitx;i++)
     92         for (int j=0;j<=limity;j++) step[i][j]=INF;
     93     int ans=INF;
     94     point in,out;
     96     memset(vis,0,sizeof(vis));
     97     step[fx][fy]=0; 
     98     in.x=fx;in.y=fy;in.num=0;
     99     priority_queue<point> que;
    100     /*由于队列记录的是经过的门数而非步数,要用优先队列*/
    101     que.push(in); 
    102     while (!que.empty())
    103     {
    104         out=que.top();
    105         que.pop();
    106         if (out.x==0 && out.y==0|| out.x==littlex || out.y==littley || out.x==limitx || out.y==limity)
    107         {
    108             return out.num;
    109         }
    110             /*如果到达终点或超出最大范围,直接输出结果*/ 
    111         for (int i=0;i<4;i++)
    112         {
    113             int nowx=out.x+dx[i],nowy=out.y+dy[i],nownum=out.num;
    114             if (nowx<0 || nowy<0 || nowx>limitx || nowy>limity) continue;
    115             if (map[out.x][out.y][i]==1) continue;
    116             /*前进的方向不能被门阻隔*/
    117             if (map[out.x][out.y][i]==2) nownum++;
    118             /*如果前进的方向是一扇门,则加一*/
    119             if (step[nowx][nowy]==INF || nownum<step[nowx][nowy]&& nownum<ans)
    120             {
    121                 in.x=nowx;in.y=nowy;in.num=nownum;
    122                 que.push(in);
    123                 step[nowx][nowy]=in.num;
    124             }
    125         } 
    126     }
    127     return -1;
    128     /*无解时返回-1*/
    129 }
    130 
    131 int main()
    132 {
    133     while (scanf("%d%d",&m,&n)) 
    134     {
    135         if (m==n && m==-1) break;
    136 
    137         initwall();
    138         initdoor();
    139         cin>>initx>>inity;
    140         fx=initx;
    141         fy=inity;
    142         /*由于方格坐标由左下角定点来表示,强制转换为int型即可*/
    143         if (n==0 && m==0||fx>199||fy>199||fx<0||fy<0)
    144            cout<<0<<endl;
    145         else cout<<bfs()<<endl;
    146     }
    147     return 0;
    148 }
  • 相关阅读:
    MSCRM 2011 自定义页面 CrmService 实现增,删,改,查需要注意的
    Microsoft Dynamics CRM 4.0,IFD验证下,自定义aspx页面,如何获取当前的用户ID ?
    CRM 4.0表单脚本开发一览
    MSCRM关于时区时间的操作
    常用JS操作方法
    详解 Visual C# 数据库编程
    Java 日志
    《信息检索导论》第二十章总结
    java文件添加包语句后的编译和运行问题
    查看端口占用情况:FPort和Moo0 ConnectionWatcher软件介绍
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/4684598.html
Copyright © 2011-2022 走看看