总结自己应用广度优先搜索(BFS)中的错误(记POJ 1376 Robot结题过程)

在尝试解决POJ 1376 Robot问题时,作者经历了错误排查的困扰。最初误以为将经过的坐标设为不可通过的点是正确做法,导致在处理机器人可连续移动多格的情况时出现问题。经过对比题解和大量测试,作者意识到应记录点的状态而非直接阻塞,最终找到解决方案。虽然程序效率不高,但能揭示BFS应用中的常见误区。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学习BFS之后以 POJ 1376 Robot(http://poj.org/problem?id=1376)作为练习,开始以为该题难度还好,但结果错了两天。特别郁闷的是竟然一直找不出错在什么地方,因为运行网上的题解在图较小的情况下没找出区别,最后碰运气花了个把小时在改图测试数据,最后发现有个图终于得出不同的数据(当时真是感动)。终于反思自己程序有什么错误,通过与题解仔细对比终于找出几个错误。

由于自己在做最基础的迷宫问题时总将经过的坐标点改成不可再通过的点(相当于墙),这里不会出错是因为这里的移动每次都是一格且没有什么方向状态。但是在POJ 1376这题中robot的移动可以是1~3格,如果经过的第一格已被改为阻塞的点那么原本可以直接走到的第2,3点都变成不可直接达到。也就是说把经过的点设置成阻塞状态并不是好主意,外加记录该点是否经过及经过的时间是个更好的主意。

下面的程序是既繁琐又效率低下,不过用来提醒自己的错误还是可以的。

#include <iostream>
#include <string>
#include <queue>
using namespace std;
//不可以将走过的地方写死,虽然在普通情况下不会出错,但是在多状态下就会发生意想不到的错误
const int MAX = 53;
const int TIMEMAX = 1<<30;
const int DIRSTATE = 4;
enum MapState{ BLOCK = 1, OBSTACLES = 0};
enum DIR{EAST = 0, SOUTH, WEST, NORTH};

const int dirxy[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

int maptime[DIRSTATE][MAX][MAX];

class Site{
public:
	Site():x(0), y(0), d(EAST){};
	Site(int tx, int ty, DIR td):x(tx), y(ty), d(td){};
	//Site& operator=(const Site& st){x=st.x, y=st.y, d=st.d; return *this;};
	int x, y;
	DIR d;
};

inline DIR getDir(string s){
	if(s == "east") return EAST;
	if(s == "south") return SOUTH;
	if(s == "west") return WEST;
	return NORTH;
}

inline bool isEmpty(int m, int n, int x, int y, const int inputMap[][MAX]){
	if(x <= 0 || y <= 0 || x >= m || y >= n){
		return false;
	}
	if(inputMap[x-1][y-1] || inputMap[x-1][y] || inputMap[x][y-1] || inputMap[x][y]){
		return false;
	}
	return true;
}

void getMap(int map[MAX][MAX], const int inputMap[][MAX], int m, int n){
	int x, y, t;
	for(x = 0; x <= m; x++){
		for(y = 0; y <= n; y++){
			map[x][y] = isEmpty(m, n, x, y, inputMap) ? OBSTACLES : BLOCK;
			for(t = EAST; t <= NORTH; t++){
				maptime[t][x][y] = TIMEMAX;
			}
		}
	}
}

int getShortestTime(int map[MAX][MAX], int m, int n, const int bx, const int by, const int ex, const int ey, DIR dir){
	if(bx <= 0 || by <= 0 || bx >= m || by >= n ||
		ex <= 0 || ey <= 0 || ex >= m || ey >= n){
		return -1;
	}
	if(BLOCK == map[ex][ey]){
		return -1;
	}/**/

	queue<Site> qsite;
	qsite.push(Site(bx, by, dir));
	maptime[dir][bx][by] = 0;
	int steptime = -1; //t is time
	int oldsize = 1, newsize = 0;
	int i, step;
	int x, y;
	Site tsite;
	while(qsite.size()){
		steptime++;
		for(i = 0; i < oldsize; i++){
			tsite = qsite.front();
			qsite.pop();

			if(ex == tsite.x && ey == tsite.y){
				return steptime;//tsite.time;
			}

		    //左右旋转
			int idir;
			for(idir = EAST; idir <= (int)NORTH; idir++){
				if(steptime+1 < maptime[idir][tsite.x][tsite.y] && (idir + tsite.d)%2){
					maptime[idir][tsite.x][tsite.y] = steptime+1;
					qsite.push(Site(tsite.x, tsite.y, (DIR)idir));
					newsize++;					
				}
			}

			//正方向前进
			/*switch(tsite.d) {
			case EAST:
				tx = 0, ty = 1;
				break;
			case SOUTH:
				tx = 1, ty = 0;
				break;
			case WEST:
				tx = 0, ty = -1;
				break;
			default:
				tx = -1, ty = 0;
			}*/

			x = tsite.x, y = tsite.y;
			for(step = 1; step <= 3; step++){
				x += dirxy[tsite.d][0];
				y += dirxy[tsite.d][1];
				if(x >0 && x < m && y >0 && y < n && OBSTACLES==map[x][y]){
					if(steptime+1 < maptime[tsite.d][x][y]){
						maptime[tsite.d][x][y] = steptime+1;
						qsite.push(Site(x, y, tsite.d));
						newsize++;
					}
				}
				else{
					break;
				}
			}
		}
		
		oldsize = newsize;
		newsize = 0;
	}
	return -1;
}

int main()
{
	int n, m;
	int inputMap[MAX][MAX], map[MAX][MAX];
	int bx, by, ex, ey;
	std::string dirct;

	while(cin>>m>>n){
		if(0==n && 0==m) break;
		int x, y;
		for(x = 0; x < m; x++){
			for(y = 0; y < n; y++){
				cin>>inputMap[x][y];
			}
		}
		getMap(map, inputMap, m, n);
		cin>>bx>>by>>ex>>ey;
		cin>>dirct;
		DIR dir = getDir(dirct);
		cout<<getShortestTime(map, m, n, bx, by, ex, ey, dir)<<endl;

	}
	return 0;
}

顺便说一下错n久的程序的错误

for(idir = EAST; idir <= (int)NORTH; idir++){
	if(OBSTACLES == map[idir][tsite.x][tsite.y] && (idir + tsite.d)%2){
		qsite.push(Site(tsite.x, tsite.y, (DIR)idir, tsite.time+1));
		newsize++;
		map[idir][tsite.x][tsite.y] = BLOCK;  //错误的改变map的状态
	}
}


for(step = 1; step <= 3; step++){
	x = tsite.x + tx*step;
	y = tsite.y + ty*step;
	if(x >0 && x < m && y >0 && y < n){
		if(OBSTACLES == map[tsite.d][x][y]){
			qsite.push(Site(x, y, tsite.d, tsite.time+1));
			newsize++;
			map[tsite.d][x][y] = BLOCK;  //同上错误的改变map的状态
		}
		else{
			break;//由于上述map状态的改变使得此处跳过一些本不该跳过的地方
		}
	}
	else{
		break;
	}
}


 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值