(转)POJ 2049 走迷宫选取经过门最少的路线 BFS搜索

Finding Nemo
Time Limit: 2000MS Memory Limit: 30000K
Total Submissions: 9778 Accepted: 2334

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. Therefore, he sent a signal to his father, Marlin, to ask for help. 
After checking the map, Marlin found that the sea is like a labyrinth with walls and doors. All the walls are parallel to the X-axis or to the Y-axis. The thickness of the walls are assumed to be zero. 
All the doors are opened on the walls and have a length of 1. Marlin cannot go through a wall unless there is a door on the wall. Because going through a door is dangerous (there may be some virulent medusas near the doors), Marlin wants to go through as few doors as he could to find Nemo. 
Figure-1 shows an example of the labyrinth and the path Marlin went through to find Nemo. 

We assume Marlin's initial position is at (0, 0). Given the position of Nemo and the configuration of walls and doors, please write a program to calculate the minimum number of doors Marlin has to go through in order to reach Nemo.

Input

The input consists of several test cases. Each test case is started by two non-negative integers M and N. M represents the number of walls in the labyrinth and N represents the number of doors. 
Then follow M lines, each containing four integers that describe a wall in the following format: 
x y d t 
(x, y) indicates the lower-left point of the wall, d is the direction of the wall -- 0 means it's parallel to the X-axis and 1 means that it's parallel to the Y-axis, and t gives the length of the wall. 
The coordinates of two ends of any wall will be in the range of [1,199]. 
Then there are N lines that give the description of the doors: 
x y d 
x, y, d have the same meaning as the walls. As the doors have fixed length of 1, t is omitted. 
The last line of each case contains two positive float numbers: 
f1 f2 
(f1, f2) gives the position of Nemo. And it will not lie within any wall or door. 
A test case of M = -1 and N = -1 indicates the end of input, and should not be processed.

Output

For each test case, in a separate line, please output the minimum number of doors Marlin has to go through in order to rescue his son. If he can't reach Nemo, output -1.

Sample Input

8 9
1 1 1 3
2 1 1 3
3 1 1 3
4 1 1 3
1 1 0 3
1 2 0 3
1 3 0 3
1 4 0 3
2 1 1
2 2 1
2 3 1
3 1 1
3 2 1
3 3 1
1 2 0
3 3 0
4 3 1
1.5 1.5
4 0
1 1 0 1
1 1 1 1
2 1 1 1
1 2 0 1
1.5 1.7
-1 -1

Sample Output

5
-1

Source

写的真的非常好!!!

很经典的BFS搜索 走迷宫选取经过门最少的路线,这题POJ测试数据设计不全面,changeDir数组赋值错误也可以过。。。

主要图的数据结构存储方式和算法实现参考了http://blog.csdn.NET/bobten2008/article/details/5093307

(1)首先是建图, 由于输入给的都是线段, 但是我们平常处理这类问题都是转换为网格来做的, 因此需要将线段转换为网格.转化的方法是对于每个格子,用其左上角点的坐标来表示这个格子。如果其左上角点的坐标是[i][j],那么这个格子就表示为[i][j].将其四周边界的四条线段归这个格子管.即为每个格子建一个数组round[i][j][4],第三维的四个位置分别表示这四条线段的类型(0-3分别对应上下左右): 数组元素的值0表示空气,1表示墙,2表示是一扇门,这样这个模型就建立好了.

(2)其次是bfs的起始点选为Nemo所在的位置,注意要将这个浮点点位置转化为格子的坐标.转化的方法很简单.对于x坐标取整即可,对于y坐标取整+1即可,比如Nemo所在位置为[1.2, 1.3]那么转化为格子的坐标即为:[1, 2].这个坐标即位bfs遍历的起始点
(3)遍历的时候如果所走的方向是墙,则不可走.如果是门则将当前总的steps数+1,如果为空气,steps数不变.另外一点就是如何判重.判重不能简单地记录有没有被访问过,而是需要记录到当前格子的最小步骤.如果当前总步骤数小于当前格子的最小步骤数,则更新其最小步骤数并将这个格子加入队列中.

(4)遍历的终止位置即为题目中的出发位置[0, 0]

Source Code

Problem: 2049 User: yangliuACMer
Memory: 1160K Time: 250MS
Language: C++ Result: Accepted
[cpp]  view plain  copy
  1. #include <iostream>  
  2. #include <queue>  
  3. #define MAX_N 210   
  4. using namespace std;  
  5.   
  6. int v[MAX_N + 1][MAX_N + 1]; //v[i][j]为到达格子[i][j]的最小步骤数  
  7. int round[MAX_N + 1][MAX_N][4]; //用左上角点的坐标来指代格子,第三维0、1、2、3指定了该数组元素对应上、下、左、右边,数组的值表明了该边的类型 0空气 1墙 2门  
  8. int wn, dn, startXI, startYI, minSteps;//wn墙数量 dn门的数量 起点对应的格子坐标  
  9. double startXF, startYF;//起点的输入浮点坐标  
  10. int dirarray[4][2] = {{0, 1}, {0, -1}, {-1, 0}, {1, 0}};//方向数组,走四个方向时坐标的变换 分别为上、下、左、右  
  11.   
  12. //加入bfs队列的元素类型  
  13. struct elem{  
  14.     //x、y为这个格子的坐标,dir记录了是从当前格子的那个方向进入到这个格子的, 上0 下1 左2 右3  
  15.     int x, y, dir, stepnum;//stepnum为到达当前格子所需要的步骤数量  
  16. };  
  17. queue<elem> bfsq;  
  18.   
  19. //取当前方向的对面方向  
  20. void changeDir(int orginal, int &newDir){  
  21.     if(orginal == 0) newDir = 1;  
  22.     else if(orginal == 1) newDir = 0;//这里下的反方向肯定是上,POJ测试用例不全面,这里改成1也能AC  
  23.     else if(orginal == 2) newDir = 3;  
  24.     else newDir = 2;  
  25. }  
  26.   
  27. //判断当前坐标是否在合法范围之内  
  28. bool inRange(int x, int y){  
  29.     return x >= 0 && x <= 205 && y >= 0 && y<= 205;  
  30. }  
  31.   
  32. void bfs(){  
  33.     //将Nemo的位置加入队列作为bfs搜索的起始位置  
  34.     while(!bfsq.empty()) bfsq.pop();  
  35.     elem curelem, newelem;  
  36.     curelem.x = startXI; curelem.y = startYI; curelem.dir = -1; curelem.stepnum = 0;  
  37.     v[startXI][startYI] = 0;  
  38.     bfsq.push(curelem);  
  39.   
  40.     int curx, cury, curdir, cursteps, newx, newy, newdir, newsteps, d;  
  41.     while(!bfsq.empty()){//实现图的广度遍历即层次式的遍历都要借助于队列  
  42.         curelem = bfsq.front();  
  43.         bfsq.pop();  
  44.         curx = curelem.x; cury = curelem.y; curdir = curelem.dir; cursteps = curelem.stepnum;  
  45.   
  46.         //到达原点  
  47.         if(curx == 0 && cury == 0){  
  48.             if(cursteps < minSteps)  
  49.                 minSteps = cursteps;  
  50.             continue;  
  51.         }  
  52.         //遍历当前格子的四个方向,尝试向四个方向走  
  53.         for(d = 0; d < 4; d++){  
  54.             //不能向回走  
  55.             if(d != curdir){  
  56.                 //所走的方向不能是墙  
  57.                 if(round[curx][cury][d] != 1){  
  58.                     //得到新的格子的坐标  
  59.                     newx = curx + dirarray[d][0];//要注意这种方向数组的用法,很巧妙!  
  60.                     newy = cury + dirarray[d][1];  
  61.   
  62.                     //判定新坐标是否在合法的范围内  
  63.                     if(inRange(newx, newy)){  
  64.                         //计算所有相对目标格子所在的方位  
  65.                         changeDir(d, newdir);  
  66.   
  67.                         //如果是门,步骤数+1  
  68.                         if(round[curx][cury][d] == 2)  
  69.                             newsteps = cursteps + 1;  
  70.                         else //如果是空气步骤数目不变  
  71.                             newsteps = cursteps;  
  72.   
  73.                         //判断当前的新格子的新状态是否需要加入队列  
  74.                         if(v[newx][newy] == 0xbf || newsteps < v[newx][newy] && newsteps < minSteps){  
  75.                             v[newx][newy] = newsteps;  
  76.                             newelem.x = newx; newelem.y = newy; newelem.stepnum = newsteps; newelem.dir = newdir;  
  77.                             bfsq.push(newelem);  
  78.                         }  
  79.                     }  
  80.                 }  
  81.             }  
  82.         }  
  83.     }  
  84. }  
  85.   
  86. int main(){  
  87.     int i, j, x, y, d, t;  
  88.     while(scanf("%d%d", &wn, &dn) && !(wn == -1 && dn == -1)){  
  89.         minSteps = INT_MAX;  
  90.         memset(v, 12, sizeof(v));  
  91.         memset(round, 0, sizeof(round));  
  92.         for(i = 1; i <= wn; i++){  
  93.             cin>>x>>y>>d>>t;  
  94.             //输入预处理,把门和墙转化为格子对应的四面边界  
  95.             if(d == 1)//与y轴平行  
  96.                 for(j = y + 1; j <= y + t; j++)//数组的值为格子类型 0为空气 1为墙 2为门  
  97.                     round[x][j][2] = round[x - 1][j][3] = 1;//第三维为方向 0上 1下 2左 3右  
  98.             else  
  99.                 for(j = x; j < x + t; j++)  
  100.                     round[j][y][0] = round[j][y + 1][1] = 1;  
  101.         }  
  102.         for(i = 1; i <= dn; i++){  
  103.             cin>>x>>y>>d;  
  104.             if(d == 1)  
  105.                 round[x][y + 1][2] = round[x - 1][y + 1][3] = 2;  
  106.             else   
  107.                 round[x][y][0] = round[x][y + 1][1] = 2;  
  108.   
  109.         }  
  110.         cin>>startXF>>startYF;//Nemo位置  
  111.         startXI = startXF;  
  112.         startYI = startYF +1;  
  113.         //一场输入处理  
  114.         if(startXI < 0 || startXI > 199 || startYI < 0 ||startYI > 199)  
  115.             cout<<0<<endl;  
  116.         else{  
  117.             bfs();  
  118.             if(minSteps == INT_MAX) cout<<"-1"<<endl;  
  119.             else cout<<minSteps<<endl;  
  120.         }  
  121.     }  
  122.     return 0;  
  123. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值