这道题要做到两点:首先是会用bfs遍历图以得到最小时间;另外,难点其实是在于如何确定那条最短路径
所经过的所有点。bfs始终层次遍历,但这样的遍历会遇到一个问题:如果每个点所花费的代价是相同的,
那么如何走并不会影响总时间。可是现在的问题是:代价并不一样。那么就会有这样一个问题:如果还是
按普通的层次遍历,那么同一层上的节点可能会抢占下一层的节点。比如,同为第二层节点的a,b(其代价
分别为6和4),共有一个第三层的节点c,同时访问c都会分别花去a,b一个代价。可是现在如果a先访问,
访问后b将不能再访问。那么c的最小代价就是7了!其实呢,是5。由此可见,同一层次上的节点,如果
有相同的下一层的邻接点则存在“遍历竞争”。解决的办法是利用优先级队列自动将b排在a之前,即使是a
先入队的。
另外一个难题就是记录路径了!得承认这个问题困扰了我很长时间!!刚开始时想用队列记录下节点,然后
再dfs找出这条路。后来想了想,dfs遍历代价可能太大了吧。为哈一直要从前向后找呢?对不对呀。于是乎,
我就用一个坐标点(father_x,father_y)记录下每个节点的来源,也即其father的坐标,那么就可以从最终点出
发,依次向前找father啦。bfs的特点就是一个father(上一层节点)可能有很多child(下一层节点),但一个
child只会有一个father。(一个child被father遍历过,就不会让其他father遍历了)
AC代码:
#include<iostream>
#include<queue>
#include<stack>
using namespace std;
const int help[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
char map[100][100];
bool visited[100][100];
int row,col,sum_time;
bool flag;
struct node //存放访问过的点的信息,自己的位置(x,y),父亲的位置(father_x,father_y)
{
int x,y,father_x,father_y,time,flag;
friend bool operator < (const node a,const node b)
{
return a.time > b.time;
}
};
priority_queue<node> q1,q2;
void store_map() //存贮图形
{
for(int i=0;i<row;i++)
{
for(int j=0;j<col;j++)
{
cin>>map[i][j];
}
}
}
void judge_empty() //由于q1,q2都是全局的,在每次使用之前都要清空
{
while(!q1.empty())
q1.pop();
while(!q2.empty())
q2.pop();
}
void bfs()
{
judge_empty(); //清空后使用
memset(visited,false,sizeof(visited));
visited[0][0]=true;
node start; //初始化队列,头结点入队
start.x=start.y=start.time=start.flag=start.father_x=start.father_y=0;
q1.push(start);
flag=false; //标志是否达到(row-1,col-1)
sum_time=0; //记录总共用去的最小时间
node tmp1,tmp2;
while(!q1.empty() && !flag)
{
tmp1=q1.top();
q1.pop();
q2.push(tmp1); //每次从q1中出对的点都要进入q2中,因为这每个点都要可能是路径上的点
for(int k=0;k<4;k++)
{
int xx=tmp1.x+help[k][0];
int yy=tmp1.y+help[k][1];
if(xx>=0 && xx<row && yy>=0 && yy<col && !visited[xx][yy]) //在图形范围内,并没有访问过的点,可以访问
{
visited[xx][yy]=true;
if(xx==row-1 && yy==col-1)
{
tmp2.x=xx;
tmp2.y=yy;
tmp2.father_x=tmp1.x;
tmp2.father_y=tmp1.y;
if(map[xx][yy]=='.')
{
tmp2.time=tmp1.time+1;
tmp2.flag=0;
}
else
{
tmp2.time=tmp1.time+1+map[xx][yy]-'0';
tmp2.flag=map[xx][yy]-'0';
}
q1.push(tmp2);
flag=true;
sum_time=tmp2.time;
if(flag) //这个最终点要在这里入q2队列
q2.push(tmp2);
}
else if(map[xx][yy]=='.')
{
tmp2.x=xx;
tmp2.y=yy;
tmp2.father_x=tmp1.x;
tmp2.father_y=tmp1.y;
tmp2.time=tmp1.time+1;
tmp2.flag=0;
q1.push(tmp2);
}
else if(map[xx][yy]>='1' && map[xx][yy]<='9')
{
tmp2.x=xx;
tmp2.y=yy;
tmp2.father_x=tmp1.x;
tmp2.father_y=tmp1.y;
tmp2.time=tmp1.time+1+map[xx][yy]-'0';
tmp2.flag=map[xx][yy]-'0';
q1.push(tmp2);
}
}
}
}
}
void help_output() //辅助输出,目的就是将q2中在路径上的点找出来,从最最终节点一直向前找其父亲节点
{
stack<node> s;
while(!q2.empty())
{
s.push(q2.top());
q2.pop();
}
node tmp,tmp1;
tmp1=s.top();
q2.push(tmp1);
s.pop();
while(!s.empty())
{
tmp=s.top();
s.pop();
if(tmp1.father_x==tmp.x && tmp1.father_y==tmp.y)
{
tmp1.father_x=tmp.father_x;
tmp1.father_y=tmp.father_y;
q2.push(tmp);
}
}
}
void output() //按要求输出
{
if(flag)
{
help_output();
cout<<"It takes "<<sum_time<<" seconds to reach the target position, let me show you the way."<<endl;
int Time=1;
node temp1,temp2;
temp1=q2.top();
q2.pop();
while(!q2.empty())
{
temp2=q2.top();
q2.pop();
cout<<Time++<<"s:("<<temp1.x<<","<<temp1.y<<")"<<"->("<<temp2.x<<","<<temp2.y<<")"<<endl;
if(temp2.flag)
{
for(int i=0;i<temp2.flag;i++)
cout<<Time++<<"s:FIGHT AT "<<"("<<temp2.x<<","<<temp2.y<<")"<<endl;
}
if(temp2.x==row-1 && temp2.y==col-1)
break;
else
{
temp1.x=temp2.x;
temp1.y=temp2.y;
}
}
}
else
cout<<"God please help our poor hero."<<endl;
cout<<"FINISH"<<endl;
}
int main()
{
while(cin>>row>>col)
{
store_map();
bfs();
output();
}
return 0;
}