今天敲了一波杭电的1010,面对迷宫一类的题目,我留在印象中的就是用栈来解决。后来查阅了一下网上的解决方法,发现用的是DFS+剪枝算法,当然,就我的代码而言,单单采用栈来敲,是不能AC的。
从某种程度上来说,我的代码就是采用栈和一定的数据结构实现了递归的DFS所具备的功能。
废话不多说,先上代码
//每个位置的探索方向按顺序依次是(左(L),上(T),右(R),下(B))
#include <iostream>
#include <stack>
#include <math.h>
using namespace std;
class Point //定义点的数据结构
{
public:
char prop; //这个点上承载的是什么(D或者X或者.)
char currentDirection; //当前要探索的方向
bool stakeState; //目前在不在栈里面
int x,y;
Point()
{
x=0;
y=0;
prop='N';
currentDirection='L';
stakeState=false;
}
};
int main()
{
Point A[100][100]={};
stack<Point> B;
int row=0;
int column=0;
int time=0;
int sx,sy; //初始点
int ex,ey; //终点
int wall=0; //X的数量
bool flag=false;
std::cin>>row>>column>>time;
while(!(row==0&&column==0&&time==0))
{
flag=false;
wall=0;
for(int i=0;i<row;i++)
{
for(int j=0;j<column;j++)
{
std::cin>>A[i][j].prop;
A[i][j].x=i;
A[i][j].y=j;
A[i][j].currentDirection='L';
A[i][j].stakeState=false;
if(A[i][j].prop=='S')
{
sx=i;
sy=j;
}
else if(A[i][j].prop=='D')
{
ex=i;
ey=j;
}
else if(A[i][j].prop=='X')
wall++;
}
}
//剪枝,剪短程序运行时间
if(((time-(abs(sx-ex)+abs(sy-ey)))%2!=0)||(time-(abs(sx-ex)+abs(sy-ey))<0)||row*column-wall<=time)
{
cout<<"NO"<<endl;
std::cin>>row>>column>>time;
continue;
}
while(1)
{
if(A[sx][sy].currentDirection=='L')
{
//下一个位置不能是越界、或者已经走过的位置(进栈了就是之间走过的)、或者障碍
if(sy-1>=0&&A[sx][sy-1].stakeState==false&&A[sx][sy-1].prop!='X')
{
time--; //用掉1s走了一步
if(A[sx][sy-1].prop=='D'&&time==0) //符合逃脱条件
{
flag=true;
break;
}
A[sx][sy].currentDirection='T'; //设置该位置下一个待探索的方向
A[sx][sy].stakeState=true; //进栈
B.push(A[sx][sy]);
sy=sy-1; //更新狗的当前位置
}
else
A[sx][sy].currentDirection='T'; //如果前面的条件不符合,直接探索当前位置的下一个方向
}
if(A[sx][sy].currentDirection=='T')
{
if(sx-1>=0&&A[sx-1][sy].stakeState==false&&A[sx-1][sy].prop!='X')
{
time--;
if(A[sx-1][sy].prop=='D'&&time==0)
{
flag=true;
break;
}
A[sx][sy].currentDirection='R';
A[sx][sy].stakeState=true;
B.push(A[sx][sy]);
sx=sx-1;
}
else
A[sx][sy].currentDirection='R';
}
if(A[sx][sy].currentDirection=='R')
{
if(sy+1<column&&A[sx][sy+1].stakeState==false&&A[sx][sy+1].prop!='X')
{
time--;
if(A[sx][sy+1].prop=='D'&&time==0)
{
flag=true;
break;
}
A[sx][sy].currentDirection='B';
A[sx][sy].stakeState=true;
B.push(A[sx][sy]);
sy=sy+1;
}
else
A[sx][sy].currentDirection='B';
}
if(A[sx][sy].currentDirection=='B')
{
if(sx+1<row&&A[sx+1][sy].stakeState==false&&A[sx+1][sy].prop!='X')
{
time--;
if(A[sx+1][sy].prop=='D'&&time==0)
{
flag=true;
break;
}
A[sx][sy].currentDirection='Q'; //Q表示4个可能的方向都已经被探索完毕
A[sx][sy].stakeState=true;
B.push(A[sx][sy]);
sx=sx+1;
}
else
A[sx][sy].currentDirection='Q';
}
//弹栈的条件(退回到上一个位置):当前位置没有可以探索的方向了或者时间用完当时没找到门(路没找对)或者
//找到门了时间不对门没开(还是路不对)
if(A[sx][sy].currentDirection=='Q'||(time==0)&&(A[sx][sy].prop!='D')||(time!=0)&&(A[sx][sy].prop=='D'))
{
if(A[sx][sy].prop=='S') //所有可能方向都试遍了
{
flag=false;
break; //出不去了
}
time++;//时间回退
A[sx][sy].currentDirection='L'; //每个位置的可探索方向被重置(就是少了这个让我卡了好久)
A[B.top().x][B.top().y].stakeState=false;
sx=B.top().x;
sy=B.top().y;
B.pop();
}
}
if(flag==false)
cout<<"NO"<<endl;
else
cout<<"YES"<<endl;
cin>>row>>column>>time;
}
}
剪枝的问题不解决的话,是不能AC的!
剪枝问题在下属博客中讲的相当清楚:
http://www.cnblogs.com/newpanderking/archive/2012/10/09/2716984.html