【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 }
时间: 2024-10-29 04:56:10

【bfs+优先队列】POJ2049-Finding Nemo的相关文章

poj2049(Finding Nemo)

题目大意: 有一片方格区域,由一米的小方格构成,方格的边可能为墙意为不能通过,可能是空白,可能是门意为可以通过,一位名叫Nemo的孩子在方格的任意位置坐标,坐标为浮点类型.问一位名叫Marlin的人至少通过几个门才能找到Nemo. 解题思路: 做了好久,刚开始没思路不知道怎么建图,后来看了看discuss,可以根据左下角的点来建图,这时只需要记住两个方向即可,记住每个点左下角上方向为"1",右方向为"0".例如:map[I][J][0] =1 意思就是i,j点的右方

POJ 2049 Finding Nemo 优先队列 STL

题目链接:http://poj.org/problem?id=2049 题目利用了<海底总动员>的情节,小丑鱼尼莫迷路了,他老爸去营救他便是题意. 题目给出了这样的地图,说是假设地图由墙和门组成,忽略墙的厚度,地图上有门,没有墙的地方是可以自由行动的问可以经过最少多少道门便可以营救到尼莫. 这个题给的数据是墙的交点为整数点,但鱼爸爸实在非墙的地方自由移动. 因此,这个题有两个难点: 1.如果建图保存地图 2.如何在地图上遍历 由于题目是给出一个点(x,y),来表示一段墙 我便用一对X,Y来表示

POJ 2049— Finding Nemo(三维BFS)10/200

海底总动员.... 这个题开始不会建图,彻底颠覆以前我对广搜题的想法.想了好久, 忽然想到省赛时HYPO让我做三维BFS来着,一直没做,看到POJ计划这个题,就是三维BFS解题,就做了一下, 对于这个题....实在不知道说什么好,又坑.又SB,POJ的后台数据和题目描述的完全不一样,看了DIscuss之后开始 改动代码,最后改的又臭又长,搜了无数题解找数据,卡了整整两天. 挥挥洒洒 160行....同时也是我第一次使用  三维建图+BFS,纪念一下! 2049 算是我攻克POJ计划的第一个卡两天

POJ 2049 Finding Nemo BFS

题目大意:给你一个奇奇怪怪的迷宫, 这个迷宫包括墙和门.再给你一个起始坐标, 问你从迷宫内到外面至少要穿越多少的门. 题目分析: 穿越多少门等同于路过了多少个格子. 为此我们可以将整个地图中的格子,门,墙,墙的交界处(格子的顶点)全部抽象成点. 即坐标(奇数,奇数)为格子的坐标,坐标(奇数,偶数)或坐标(偶数,奇数)为门或墙的坐标,坐标(偶数,偶数)为格子的顶点. 这样题目就转化成了从起始点所在的格子走到迷宫外的格子最少要经过多少个格子,用step[i][j]表示走出迷宫后遇到的第一个格子的坐标

POJ 2049 Finding Nemo

Finding Nemo Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 8631   Accepted: 2019 Description Nemo is a naughty boy. One day he went into the deep sea all by himself. Unfortunately, he became lost and couldn't find his way home. Therefo

【POJ 2049】Finding Nemo

[POJ 2049]Finding Nemo 迷宫类Bfs,不同于之前的是之前是点 这次是房间,我的做法是把每个房间看做一个点(移动地图使房间为整型坐标 便于用数组下表表示房间坐标) 上下左右是墙/门/无用1 0 -1表示 然后Bfs遍历即可 坑点有x/y<0 和x/y > 199的情况 贡献了好多个RE 上代码 #include <cstdio> #include <cstring> #include <queue> using namespace std

[ACM] hdu 1242 Rescue (BFS+优先队列)

Rescue Problem Description Angel was caught by the MOLIGPY! He was put in prison by Moligpy. The prison is described as a N * M (N, M <= 200) matrix. There are WALLs, ROADs, and GUARDs in the prison. Angel's friends want to save Angel. Their task is:

Battle City BFS+优先队列

Battle City Many of us had played the game "Battle city" in our childhood, and some people (like me) even often play it on computer now. What we are discussing is a simple edition of this game. Given a map that consists of empty spaces, rivers,

hdu 1242 Rescue(bfs+优先队列)

Angel was caught by the MOLIGPY! He was put in prison by Moligpy. The prison is described as a N * M (N, M <= 200) matrix. There are WALLs, ROADs, and GUARDs in the prison. Angel's friends want to save Angel. Their task is: approach Angel. We assume