1. 程式人生 > >UVA439-最短路-BFS

UVA439-最短路-BFS

前一段時間學BFS(寬度優先搜尋)最短路的時候,紫書上那個題感覺太複雜了,debug了幾天。。。還好最後AC了。

今天發現一個簡單的題,而且還覺得挺有意思的,用這個題來學BFS最短路我覺得更合適。這道題題意簡單,輸入輸出也簡單,所以程式碼較短。

分析:

 第一次看到用bfs求最短路的程式碼感覺很神奇,竟然還可以這樣做。在沒有學bfs之前,我都是用dfs遍歷所有路找出最短的(超時難免了)。bfs可以用佇列實現,要做的就是把當前所在節點的所有下一個節點入列,這樣就保證了從佇列讀取出來的節點都是第n步或者n+1步了,直到發現終點為止,這條路就是最短路。

實現這個思路有幾個巧妙的地方,就是該怎麼找第n+1個節點。在這道題中,下一個節點可能有8個,用迴圈可以構造出這8個節點出來(詳情見程式碼)。當然8個節點並不是都可以,超出棋盤的去掉,已經入過列的節點去掉。

還有個問題就是怎麼算走了多少步。我把這個資料存在一個8*8陣列中,每個節點一定有唯一的步數,並且還順便把這個陣列用來判斷一個節點是否走過。

實現程式碼: 

其中的vis陣列很關鍵,構造下一個節點程式碼部分較巧妙。

#include<cstdio>
#include<queue>
#include<cstring>
#include<cstdlib>
struct Point
{
    Point(int r,int c):r(r),c(c) {}
    int r,c;
};

char s1[3],s2[3];
int vis[8][8],begin_r,begin_c,end_r,end_c;

int bfs()
{
    memset(vis,0,sizeof(vis));
    vis[begin_r][begin_c]=1;
    std::queue<Point> q;
    Point p(begin_r,begin_c);
    q.push(p);

    while(!q.empty())
    {
        p=q.front();
        q.pop();
        if(p.r==end_r&&p.c==end_c)
            break;
        for(int i=-2; i<3; ++i)
            for(int j=-2; j<3; ++j)
                if(i&&j&&abs(i)!=abs(j)&&p.r+i>-1&&p.r+i<8&&
                   p.c+j>-1&&p.c+j<8&&!vis[p.r+i][p.c+j])
                   {
                        vis[p.r+i][p.c+j]=vis[p.r][p.c]+1;
                        q.push(Point(p.r+i,p.c+j));
                   }
    }
    return vis[p.r][p.c]-1;
}
int main()
{
    while(scanf("%s",s1)==1)
    {
        begin_r=s1[0]-'a';
        begin_c=s1[1]-'1';
        scanf("%s",s2);
        end_r=s2[0]-'a';
        end_c=s2[1]-'1';
        printf("To get from %s to %s takes %d knight moves.\n",s1,s2,bfs());
    }
}