学习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;
}
}