這道題要做到兩點:首先是會用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;}}}elsecout<<"God please help our poor hero."<<endl;cout<<"FINISH"<<endl;}int main(){while(cin>>row>>col){store_map();bfs(); output();}return 0;}