Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 9803 Accepted Submission(s): 2922
Special Judge
#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
int visit[111][111],n,m,s,xx[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; //visit用来记录访问过的点,xx是本人习惯性的方向数组0^^0
char map[111][111]; //map就是输入的那个地图
struct ssss
{
int x,y,time;
}ss,up[111][111]; //ss是用来临时跟队列内容进行交流的,比如入队出队,up就是我的精华了,记录当前点的指向和时间
queue<ssss> q,qq; //弄俩队列,后者用来初始化前者的
/*void cmp() //这个是我用来实时监测up数组的变换啊,就是每次队列的循环我都把整个up打印出来看我的代码的运作
{
int i,j;
for(i=0;i<n;i++){
for(j=0;j<m;j++)
cout<<up[i][j].x<<up[i][j].y<<up[i][j].time<<" ";cout<<endl;}cout<<endl;
}*/
void bfs()
{
int i,X,x,Y,y,time;
while(!q.empty()) //队列非空
{
ss=q.front();q.pop(); //用ss取出队首并删除队首
X=ss.x;Y=ss.y;time=ss.time; //用X记录ss中的x,Y记录ss中的y,time记录ss中的time,因为后面要入队会利用到ss,所以我提前存好数据
if(time) //这个就是其关键左右的东西了,简单吧?只要当前点的时间不是0,那就把时间减一再入队,嘿嘿,直到时间为0才可以继续向下走,这就迎合上来题目中的怪物啊,你有多少血,我就陪你入队多少次,你死了,大爷再前进
{
ss.time=time-1;q.push(ss);continue;
}
if(X==0&&Y==0) //到了起点时就可以处理好并结束广搜了
{
if(map[X][Y]>'0'&&map[X][Y]<='9') //因为起点可能也有怪物,所以这个步骤也还是少不得的
up[X][Y].time=map[X][Y]-48;
s=1;return;
}
for(i=0;i<4;i++)
{
x=X+xx[i][0];
y=Y+xx[i][1];
if(x>=0&&y>=0&&x<n&&y<m&&visit[x][y]&&map[x][y]!='X') //判断是否在界内,是否已访问,是否为陷阱
{
visit[x][y]=0;up[x][y].time=up[X][Y].time+1;ss.time=0; //标记为已访问,up内的时间+1,入队的时间初始化为0
if(map[x][y]>'0'&&map[x][y]<='9') //如果是有怪物
up[x][y].time+=map[x][y]-48,ss.time+=map[x][y]-48; //up内的时间再把杀死怪物的时间加上去,入队的时间就记录杀死怪物的时间
up[x][y].x=X;up[x][y].y=Y; //把up内的坐标指向处理好,也就是(x,y)是(X,Y)搜索周围得到的,因此(x,y)要指向(X,Y)
ss.x=x;ss.y=y;q.push(ss); //把入队的坐标处理好并入队
}
}
}
}
int main (void)
{
int i,j,k,l,x,y;
while(cin>>n>>m)
{
for(i=0;i<n;i++)
for(j=0;j<m;j++)
cin>>map[i][j],visit[i][j]=1,up[i][j].x=up[i][j].y=up[i][j].time=0; //输入map并且初始化up数组还有visit
q=qq;ss.x=n-1;ss.y=m-1;ss.time=0;q.push(ss);s=0;visit[n-1][m-1]=0; //初始化队列,终点的坐标时间打包存入队列并标记它为已访问
if(map[n-1][m-1]>'0'&&map[n-1][m-1]<='9')up[n-1][m-1].time=map[n-1][m-1]-48; //终点如果也有怪物,那么up内的time也要记录
bfs();
if(s)
{
printf("It takes %d seconds to reach the target position, let me show you the way.\n",up[0][0].time); //因为是从尾到首搜索到,所以时间是从尾到首递增,所以总时间是记录在up[0][0]的
i=j=0;l=1; //用i和j从起点回溯,l代表时间
while(i!=n-1||j!=m-1) //一定要用“||”不然可能走到最右边或者最下边就会结束的
{
x=up[i][j].x;y=up[i][j].y;k=up[i][j].time-up[x][y].time-1; //x,y记录下一个点的坐标,k是这点的时间和下一点的时间差减一,因为走一步也要时间的
while(k-->0) //接下来的k分钟就老老实实留在这里打怪好了,哦耶~
printf("%ds:FIGHT AT (%d,%d)\n",l++,i,j);
printf("%ds:(%d,%d)->(%d,%d)\n",l++,i,j,x,y);
i=x;j=y;
}
k=up[i][j].time; //完了之后可没完全完,终点可能是有怪的,所以也要看一看,不然前面就白处理了呗
while(k--)
printf("%ds:FIGHT AT (%d,%d)\n",l++,i,j);
}else puts("God please help our poor hero.");
puts("FINISH");
}
return 0;
}
我是从终点开始向起点广搜的,因为我从一个点搜索周围不可能同时指向四个方向啊,就算可以怎么去区分我要的路线?从起点开始又还要回溯把这条路“打通”懂?本来指向就是单向的,而且还和我要的效果正好相反,多麻烦啊,所以大爷就直接反着搞,省时省力更省心,省省更健康,哦耶~