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

很经典的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
#include <iostream> #include <queue> #define MAX_N 210 using namespace std; int v[MAX_N + 1][MAX_N + 1]; //v[i][j]为到达格子[i][j]的最小步骤数 int round[MAX_N + 1][MAX_N][4]; //用左上角点的坐标来指代格子,第三维0、1、2、3指定了该数组元素对应上、下、左、右边,数组的值表明了该边的类型 0空气 1墙 2门 int wn, dn, startXI, startYI, minSteps;//wn墙数量 dn门的数量 起点对应的格子坐标 double startXF, startYF;//起点的输入浮点坐标 int dirarray[4][2] = {{0, 1}, {0, -1}, {-1, 0}, {1, 0}};//方向数组,走四个方向时坐标的变换 分别为上、下、左、右 //加入bfs队列的元素类型 struct elem{ //x、y为这个格子的坐标,dir记录了是从当前格子的那个方向进入到这个格子的, 上0 下1 左2 右3 int x, y, dir, stepnum;//stepnum为到达当前格子所需要的步骤数量 }; queue<elem> bfsq; //取当前方向的对面方向 void changeDir(int orginal, int &newDir){ if(orginal == 0) newDir = 1; else if(orginal == 1) newDir = 0;//这里下的反方向肯定是上,POJ测试用例不全面,这里改成1也能AC else if(orginal == 2) newDir = 3; else newDir = 2; } //判断当前坐标是否在合法范围之内 bool inRange(int x, int y){ return x >= 0 && x <= 205 && y >= 0 && y<= 205; } void bfs(){ //将Nemo的位置加入队列作为bfs搜索的起始位置 while(!bfsq.empty()) bfsq.pop(); elem curelem, newelem; curelem.x = startXI; curelem.y = startYI; curelem.dir = -1; curelem.stepnum = 0; v[startXI][startYI] = 0; bfsq.push(curelem); int curx, cury, curdir, cursteps, newx, newy, newdir, newsteps, d; while(!bfsq.empty()){//实现图的广度遍历即层次式的遍历都要借助于队列 curelem = bfsq.front(); bfsq.pop(); curx = curelem.x; cury = curelem.y; curdir = curelem.dir; cursteps = curelem.stepnum; //到达原点 if(curx == 0 && cury == 0){ if(cursteps < minSteps) minSteps = cursteps; continue; } //遍历当前格子的四个方向,尝试向四个方向走 for(d = 0; d < 4; d++){ //不能向回走 if(d != curdir){ //所走的方向不能是墙 if(round[curx][cury][d] != 1){ //得到新的格子的坐标 newx = curx + dirarray[d][0];//要注意这种方向数组的用法,很巧妙! newy = cury + dirarray[d][1]; //判定新坐标是否在合法的范围内 if(inRange(newx, newy)){ //计算所有相对目标格子所在的方位 changeDir(d, newdir); //如果是门,步骤数+1 if(round[curx][cury][d] == 2) newsteps = cursteps + 1; else //如果是空气步骤数目不变 newsteps = cursteps; //判断当前的新格子的新状态是否需要加入队列 if(v[newx][newy] == 0xbf || newsteps < v[newx][newy] && newsteps < minSteps){ v[newx][newy] = newsteps; newelem.x = newx; newelem.y = newy; newelem.stepnum = newsteps; newelem.dir = newdir; bfsq.push(newelem); } } } } } } } int main(){ int i, j, x, y, d, t; while(scanf("%d%d", &wn, &dn) && !(wn == -1 && dn == -1)){ minSteps = INT_MAX; memset(v, 12, sizeof(v)); memset(round, 0, sizeof(round)); for(i = 1; i <= wn; i++){ cin>>x>>y>>d>>t; //输入预处理,把门和墙转化为格子对应的四面边界 if(d == 1)//与y轴平行 for(j = y + 1; j <= y + t; j++)//数组的值为格子类型 0为空气 1为墙 2为门 round[x][j][2] = round[x - 1][j][3] = 1;//第三维为方向 0上 1下 2左 3右 else for(j = x; j < x + t; j++) round[j][y][0] = round[j][y + 1][1] = 1; } for(i = 1; i <= dn; i++){ cin>>x>>y>>d; if(d == 1) round[x][y + 1][2] = round[x - 1][y + 1][3] = 2; else round[x][y][0] = round[x][y + 1][1] = 2; } cin>>startXF>>startYF;//Nemo位置 startXI = startXF; startYI = startYF +1; //一场输入处理 if(startXI < 0 || startXI > 199 || startYI < 0 ||startYI > 199) cout<<0<<endl; else{ bfs(); if(minSteps == INT_MAX) cout<<"-1"<<endl; else cout<<minSteps<<endl; } } return 0; }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值