LA 5966 Blade and Sword (雙向bfs + 想法) - from lanshui_Yang

  

題目大意:給你一張有n * m個網格的圖,每個網格可能是如下符號:

“#”:牆

“P”:出發點

“D”:終點

“.”:空地

“*”:傳送機

有一個旅行家(假設名叫Mike),他要從點P到達點D,途中必須遵循如下規則:

1、  Mike可以走到空地(“.”),但不可通過牆(“#”)。

2、  Mike也可以走到傳送機(“*”),但是當他第一次到達傳送機時,下一步只有一種選擇:他必須選擇到達另一個傳送機,然後,下一步會有兩種選擇:

              一、走到相鄰的可去的格子中。

              二、選擇到達另一個傳送機,然後遵循同樣的規則。

讓你計算出Mike從點P到點D的最少步數,如果不能到達,就輸出“impossible”。

解題思路:Mike從點P到達點D只可能有兩種方式:

1、  經過傳送機(“*”), 但圖中必須有兩個或兩個以上的傳送機。

2、  不經過傳送機,只經過空地(“.”)。

所以只需找出兩種方式所需步數的最小值即可。

    Ps:程序後面有幾組我自己的測試樣例,請仔細理解。

具體解法請看程序:

#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
#define PI acos(-1.0)
#define inf 0x3fffffff
#define mem(a,b) memset(a,b,sizeof(a))

using namespace std;
const int MAXN = 205 ;
char s[MAXN][MAXN] ;
bool vis[MAXN][MAXN] ;
int dP[MAXN][MAXN] ; // 記錄點P到每個點網格中每個點(中間不經過“*”)的最短距離
int dD[MAXN][MAXN] ; // 記錄點D到每個點網格中每個點(中間不經過“*”)的最短距離
int ci[MAXN][MAXN] ; // 記錄每個“*”點是否能從點P或點D到達。
int ca ;
int m , n ;
int te ;   // 統計矩陣中的 “*” 數量。
int X[4] = {0 , 0 , 1 , -1} ; // 四個方向
int Y[4] = {1 , -1 , 0 , 0} ;
int MIN ;  // 記錄從點P 到 點D 距離的最小值
struct Node
{
    int x ;
    int y ;
};
Node c , e ;  // c代表點P ,e 代表 點D

struct Kx // 記錄 每個可達的 “*”到點P 和 到點D的最近距離
{
    int x ;
    int y ;
    int d ;
} kkP[MAXN * MAXN] , kkD[MAXN * MAXN] ;
int cntP , cntD ;
void init() // 輸入
{
    scanf("%d%d" , &m , &n) ;
    mem(ci , 0) ;
    int i , j ;
    te = 0 ;
    for(i = 0 ; i < m ; i ++)
    {
        scanf("%s" , s[i]) ;
        for(j = 0 ; j < n ; j ++)
        {
            if(s[i][j] == '*')
            {
                te ++ ;
            }
            else if(s[i][j] == 'P')
            {
                c.x = i ;
                c.y = j ;
            }
            else if(s[i][j] == 'D')
            {
                e.x = i ;
                e.y = j ;
            }
        }
    }
}
queue<Node> q ;
int cango1(int x , int y)
{
    if(x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && ((s[x][y] == '.' || s[x][y] == 'D')))
        return 1 ;
    return 0 ;
}
int cango2(int x , int y)
{
    if(x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && s[x][y] != '#')
        return 1 ;
    return 0 ;
}
bool flag ; // 判斷點P是否能不經過點 “*” 到達 點D 。
void bfs(int i , int j , int bb) // 從點P bfs
{
    while (!q.empty()) q.pop() ;
    Node tmp ;
    tmp.x = i ;
    tmp.y = j ;
    q.push(tmp) ;
    vis[i][j] = true ;
    while (!q.empty())
    {
        tmp = q.front() ;
        q.pop() ;
        int k ;
        int tx , ty ;
        for(k = 0 ; k < 4 ; k ++)
        {
            Node tp2 ;
            tx = tmp.x + X[k] ;
            ty = tmp.y + Y[k] ;
            if(bb == 1)
            {
                if(cango1(tx , ty))
                {
                    dP[tx][ty] = dP[tmp.x][tmp.y] + 1 ;
                    if(tx == e.x && ty == e.y)
                        flag = true ;
                    vis[tx][ty] = true ;
                    tp2.x = tx ;
                    tp2.y = ty ;
                    q.push(tp2) ;
                }
            }
            else
            {
                if(cango2(tx , ty))
                {
                    dP[tx][ty] = dP[tmp.x][tmp.y] + 1 ;
                    if(s[tx][ty] == '*')
                    {
                        ci[tx][ty] ++ ;
                        ++ cntP ;
                        kkP[cntP].x = tx ;
                        kkP[cntP].y = ty ;
                        kkP[cntP].d = dP[tx][ty] ;
                    }
                    if(tx == e.x && ty == e.y)
                        flag = true ;
                    vis[tx][ty] = true ;
                    tp2.x = tx ;
                    tp2.y = ty ;
                    if(s[tx][ty] != '*')  // 注意此處
                        q.push(tp2) ;
                }
            }
        }
    }
}
void bfs2(int i , int j ) // 從點D bfs
{
    while (!q.empty()) q.pop() ;
    Node tmp ;
    tmp.x = i ;
    tmp.y = j ;
    q.push(tmp) ;
    vis[i][j] = true ;
    while (!q.empty())
    {
        tmp = q.front() ;
        q.pop() ;
        int k ;
        int tx , ty ;
        for(k = 0 ; k < 4 ; k ++)
        {
            Node tp2 ;
            tx = tmp.x + X[k] ;
            ty = tmp.y + Y[k] ;
            if(cango2(tx , ty))
            {
                dD[tx][ty] = dD[tmp.x][tmp.y] + 1 ;
                if(s[tx][ty] == '*')
                {
                    ci[tx][ty] ++ ;
                    ++ cntD ;
                    kkD[cntD].x = tx ;
                    kkD[cntD].y = ty ;
                    kkD[cntD].d = dD[tx][ty] ;
                }
                vis[tx][ty] = true ;
                tp2.x = tx ;
                tp2.y = ty ;
                if(s[tx][ty] != '*') // 注意此處
                    q.push(tp2) ;
            }
        }
    }
}

void solve()
{
    printf("Case %d: " , ++ ca) ;
    flag = false ;
    mem(dP , 0) ;
    mem(dD , 0) ;
    mem(vis , 0) ;
    cntP = cntD = -1 ;
    if(te <= 1)
    {
        bfs(c.x , c.y , 1) ;
    }
    else
    {
        bfs(c.x , c.y , 2) ;
        mem(vis , 0) ;
        bfs2(e.x , e.y) ;
    }
    int i , j ;
    MIN = inf ;
    if(te > 1)  // 注意此處,想一想
    {
        for(i = 0 ; i < m ; i ++)
        {
            for(j = 0 ; j < n ; j ++)
            {
                if(ci[i][j] > 1)
                {
                    if(MIN > dP[i][j] + dD[i][j] + 2)
                        MIN = dP[i][j] + dD[i][j] + 2 ;
                }
            }
        }
    }
    if(flag)
    {
        if(te <= 1)
        {
            if(MIN >  dP[e.x][e.y])
                MIN =  dP[e.x][e.y] ;
            printf("%d\n" , MIN) ;
        }
        else
        {
            MIN = min(MIN , dP[e.x][e.y]) ;
            if(cntP >= 0 && cntD >= 0)
            {
                if(kkD[0].x == kkP[0].x && kkD[0].y == kkP[0].y)
                {
                    if(cntP > 0)
                    {
                        MIN = min(MIN , kkP[1].d + kkD[0].d + 1) ;
                    }
                    if(cntD > 0)
                    {
                        MIN = min(MIN , kkP[0].d + kkD[1].d + 1) ;
                    }
                }
                else
                {
                    MIN = min(MIN , kkD[0].d + kkP[0].d + 1) ;
                }
            }
            printf("%d\n" , MIN) ;
        }
    }
    else
    {
        if(te <= 1)
        {
            puts("impossible") ;
            return ;
        }
        else
        {
            if(cntP < 0 || cntD < 0)
            {
                puts("impossible") ;
                return ;
            }
            if(kkD[0].x == kkP[0].x && kkD[0].y == kkP[0].y)
            {
                if(cntP > 0)
                {
                    MIN = min(MIN , kkP[1].d + kkD[0].d + 1) ;
                }
                if(cntD > 0)
                {
                    MIN = min(MIN , kkP[0].d + kkD[1].d + 1) ;
                }
            }
            else
            {
                MIN = min(MIN , kkD[0].d + kkP[0].d + 1) ;
            }
            printf("%d\n" , MIN) ;
            return ;
        }
    }
}

int main()
{
    int T ;
    scanf("%d" , &T) ;
    while (T --)
    {
        init() ;
        solve() ;
    }
    return 0 ;
}

/*
9
4 10
##########
#.P..#*..#
#*......D#
##########
3 9
#########
#P.#..D.#
#########
3 7
#######
#P*D#*#
#######
3 8
########
P*.#..D#
####*###
3 5
#####
#P.D#
#####
3 5
#####
#P*D#
#####
3 5
#####
#P..#
#####
5 10
##########
#.P..#*..#
#.....####
#*......D#
##########
3 9
#########
#P*D...*#
#########

*/


 

 

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