POJ4115:鳴人和佐助(廣搜)

POJ4115:鳴人和佐助

描述
已知一張地圖(以二維矩陣的形式表示)以及佐助和鳴人的位置。地圖上的每個位置都可以走到,只不過有些位置上有大蛇丸的手下,需要先打敗大蛇丸的手下才能到這些位置。鳴人有一定數量的查克拉,每一個單位的查克拉可以打敗一個大蛇丸的手下。假設鳴人可以往上下左右四個方向移動,每移動一個距離需要花費1個單位時間,打敗大蛇丸的手下不需要時間。如果鳴人查克拉消耗完了,則只可以走到沒有大蛇丸手下的位置,不可以再移動到有大蛇丸手下的位置。佐助在此期間不移動,大蛇丸的手下也不移動。請問,鳴人要追上佐助最少需要花費多少時間?

輸入
輸入的第一行包含三個整數:M,N,T。代表M行N列的地圖和鳴人初始的查克拉數量T。0 < M,N < 200,0 ≤ T < 10
後面是M行N列的地圖,其中@代表鳴人,+代表佐助。*代表通路,#代表大蛇丸的手下。

輸出
輸出包含一個整數R,代表鳴人追上佐助最少需要花費的時間。如果鳴人無法追上佐助,則輸出-1。

樣例輸入

樣例輸入1
4 4 1
#@##
**##
###+
****

樣例輸入2
4 4 2
#@##
**##
###+
****

樣例輸出

樣例輸出1
6

樣例輸出2
4

思路:

  • 首先此題是一個迷宮問題,是從某一個點要到某一個點,在這中間呢,又加入了消耗查克拉這個條件,我們可以按照深搜+剪枝來做,也可以直接用廣搜來找最短路。

  • 那麼這道題的狀態是什麼?是又鳴人的所在位置以及鳴人所剩查克拉決定的,(i,j,n),初始狀態是(i0,j0,N),終止狀態是(i,i,n),達到佐助位置即可。因爲用廣搜,所以到達即是最短。

  • 另外我們需要判重,用深搜只需要看這個點有沒有走過,用廣搜的話就要加入查克拉的消耗情況,所以是三維的visit數組。

AC代碼

    #include<iostream>
    #include<cstdio>
    #include<queue>
    using namespace std;

    struct Node
    {
        int r,c;   //所在位置 
        int t;     //查克拉剩餘
        int level; //所在層數,路徑長度 
    };

    char map[210][210];          //地圖
    int visit[210][210][15] = {0};    //判重數組
    int M,N,T;                  //地圖大小,查克拉數量 

    int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};   //方向數組  

    int main()
    {
        //分別代表鳴人和佐助的位置 
        int r1,c1;
        int r2,c2;

        scanf("%d %d %d",&M,&N,&T);
        for(int i = 0 ; i < M ; i ++)
        {
            for(int j = 0 ; j < N ; j ++)
            {
                cin>>map[i][j];
                if(map[i][j] == '@')
                {
                    r1 = i;
                    c1 = j;
                }

                if(map[i][j] == '+')
                {
                    r2 = i;
                    c2 = j;
                }
            }
        }

        visit[r1][c1][T] = 1;
        queue<struct Node> q;

        //初始狀態入隊
        Node node;
        node.r = r1; node.c = c1; node.level = 0; node.t = T;
        q.push(node);

        while(!q.empty())
        {
            Node temp = q.front();
            q.pop();

            //找到了 
            if(temp.r == r2 && temp.c == c2)
            {
                printf("%d\n",temp.level);
                return 0;   
            }   

            //沒找到 入隊所有關聯節點
            for(int i = 0 ; i < 4 ; i ++)
            {
                Node temp2;
                temp2.r = temp.r + dir[i][0];
                temp2.c = temp.c + dir[i][1];
                if(temp2.r >= 0 && temp2.r < M && temp2.c >= 0 && temp2.c < N)
                {
                    //不越界

                    //若爲# 並且查克拉夠 並且沒訪問過 可訪問 
                    if(map[temp2.r][temp2.c] == '#' && temp.t >= 1 && visit[temp2.r][temp2.c][temp.t - 1] == 0 )
                    {
                        temp2.t = temp.t - 1;
                        temp2.level = temp.level + 1;
                        q.push(temp2);
                        visit[temp2.r][temp2.c][temp2.t] = 1; 
                    } 

                    //不是# 並且未訪問過 
                    else if(map[temp2.r][temp2.c] != '#' && visit[temp2.r][temp2.c][temp.t] == 0)
                    {
                        temp2.t = temp.t;
                        temp2.level = temp.level + 1;
                        q.push(temp2);
                        visit[temp2.r][temp2.c][temp2.t] = 1;
                    }

                }
            }

        } 

        //找不到 
        cout<<-1<<endl;

        return 0;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章