XJOI 3585 The rescue plan 营救计划 题解

英文

Time Limit:1s Memory Limit:256M

Description

Given a n*m map.A “Mengxin” is trapped.You are the one to rescue him.In the map,there are some guards,you must defeat the guards to get your way.Defeat one guard takes 1 min,move one step takes 1 min,each step you can only take one of 4 directions(up,down,left,right).Please tell us the least time you cost to rescue the guy.

Input

The first line contains two integers n,m
The next n lines,each line input m characters represent the map. 1<=n,m<=200
‘@’ is your position
‘#’ is obstacle
‘.’ means there is a way you can go
‘G’ means guard
‘M’ means the position of “Mengxin”.

Output

If you can save this guy,output the least time you cost,else,output “You can’t save Mengxin”

Sample Input1

7 8 
#.#####. 
#.M#..@. 
#..#G... 
..#..#.# 
#...##.. 
.#...... 
........

Sample Output1

13

Sample Input2

2 2
M.
G@

​Sample Output2

2

中文

时间:1s 空间:128M

题目描述:

在一个n∗m的迷宫里,有一个萌新被困住了,你作为一个久经码场的战士,决定去营救萌新。地图中还会有一些守卫,你必须打败守卫才能通过守卫所在的位置,打败守卫需要花费1分钟,移动一步需要花费一分钟,每次你只能往上下左右某个方向移动一步。问你最少需要花费多少时间才能救到萌新。

输入格式:

第一行输入两个整数 n,m
接下来n行每行输入m个字符
‘#’代表障碍物,无法直接通过
‘.’代表空地,可以直接通过
‘G’代表守卫,你需要打败他才能通过
‘M’代表萌新所在的位置
‘@’表示你所在的位置

输出格式:

如果可以营救到萌新,就输出最少需要花费的分钟数
如果不可以,输出“You can’t save Mengxin”

样例输入1:

7 8 
#.#####. 
#.M#..@. 
#..#G... 
..#..#.# 
#...##.. 
.#...... 
........

样例输出1:

13

样例输入2:

2 2
M.
G@

样例输出2:

2

约定:

1<=n,m<=200

注意:

以上输入样例中,用到的代码片不是代码,只是为了方便表示,谢谢。

提示:

这道题求的是最优解,很容易就想到广度优先搜索(又称宽度优先搜,BFS),最先在队列里遇到的答案一定就是最优解了。广度优先搜索用队列实现,用队列的left来扩展right来维持搜索。但还有一些小困难,比如打败守卫要1分钟的问题。如何解决呢?我们可以假设我们去营救她时,拥有一个技能可以秒杀有守卫,这个技能要蓄力1分钟,这是不是好理解一些呢?如果单纯的认为经过守卫的点耗时2min,博主认为第一个扫到的终点不一定是最优解(个人观点,未经尝试)。请看代码中的注解吧。具体代码如下:

代码:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#define N 200
using namespace std ;
struct mrz
{
    int x , y , z ;//x,y还是表示坐标,z表示到该坐标时的时间
    bool jn ;//jn时技能是否蓄力。初始条件是jn=0,当在原地停留1min后,jn=1,打打掉守卫后,jn=0;
//我们不用当心蓄力后还不打,却绕路的问题,因为这肯定不是最优解。如果蓄力后,绕路以后再打,也是可以的,不影响答案
} p [ N * N + 1 ] ;
int x_c , y_c , x_z , y_z , n , m , l = 1 , r = 1 , ans = N*N*N ;
int mp [ N + 1 ] [ N + 1 ] ;//查看地图上的点是否走过
bool pd_a ( int k1 , int k2 )//判断是否达到目标
{
    if ( k1 == x_z && k2 == y_z ) return true ;
    else return false ;
}
bool pd_b ( int k1 , int k2 )//判断该点是否可以走
{
    if ( k1 >= 1 && k1 <= n && k2 >= 1 && k2 <= m && mp [ k1 ] [ k2 ] != 0 ) return true ;
    else return false ;
}
int main ( )
{

    scanf ( "%d%d" , & n , & m ) ;
    char c ;
    memset ( p , 0 , sizeof ( p ) ) ;
    memset ( mp , 0 , sizeof ( mp ) ) ;
    for ( int i = 1 ; i <= n ; i ++ )  
        for ( int j = 1 ; j <= m ; j ++)//生成地图
        {
            cin >> c ;
            if ( c == '.' || c == 'M' ) mp [ i ] [ j ] = 1 ;
            if ( c == 'M' )
            {
                x_z = i ;
                y_z = j ;
            }
            if ( c == '@' )
            {
                x_c = i ;
                y_c = j ;
            }
            if ( c == 'G' ) mp [ i ] [ j ] = 2 ;
        }
    p [ 1 ] . x = x_c ;
    p [ 1 ] . y = y_c ;
    while ( l <= r)
    {
//      cout << p [ l ] . x << " " << p [ l ] . y << " " << p [ l ] . z << endl ;
//      for ( int i = 1 ; i <= n ; i ++ )
//      {
//          for ( int j = 1 ; j <= m ; j ++ ) cout << mp [ i ] [ j ] ;
//          cout << endl ;
//      }
//      system ( "pause" ) ;
//      以上代码可以调时使用
        if ( pd_b ( p [ l ] . x + 1 , p [ l ] . y ) == true )
        {
            r ++ ;
            if ( mp [ p [ l ] . x + 1 ] [ p [ l ] . y ] == 1 )
            {  //最正常的情况,走空地
                p [ r ] . x = p [ l ] . x + 1 ;
                p [ r ] . y = p [ l ] . y ;
                p [ r ] . z = p [ l ] . z + 1 ;
                p [ r ] . jn = p [ l ] . jn ;
                mp [ p [ r ] . x ] [ p [ r ] . y ] = 0 ;
            } else
            {
                if ( p [ l ] . jn == 0 )
                {   //前方有守卫,还未蓄力
                    p [ r ] . x = p [ l ] . x ;
                    p [ r ] . y = p [ l ] . y ;//原地不动
                    p [ r ] . z = p [ l ] . z + 1 ;//耗时1min
                    p [ r ] . jn = 1 ;//蓄力
                } else
                {//前方有守卫,蓄力完成
                    p [ r ] . x = p [ l ] . x + 1 ;
                    p [ r ] . y = p [ l ] . y ;
                    p [ r ] . z = p [ l ] . z + 1 ;
                    mp [ p [ r ] . x ] [ p [ r ] . y ] = 0 ;
                    p [ r ] . jn = 0 ;
                }
            }
            if ( pd_a ( p [ r ] . x , p [ r ] . y ) == true && p [ r ] . z < ans )
            {
                ans = p [ r ] . z ;
            }  //判断答案
        }//以下是其他方向。广搜代码虽长,但大同小异。
        if ( pd_b ( p [ l ] . x - 1 , p [ l ] . y ) == true )
        {
            r ++ ;
            if ( mp [ p [ l ] . x - 1 ] [ p [ l ] . y ] == 1 )
            {
                p [ r ] . x = p [ l ] . x - 1 ;
                p [ r ] . y = p [ l ] . y ;
                p [ r ] . z = p [ l ] . z + 1 ;
                p [ r ] . jn = p [ l ] . jn ;
                mp [ p [ r ] . x ] [ p [ r ] . y ] = 0 ;
            } else
            {
                if ( p [ l ] . jn == 0 )
                {
                    p [ r ] . x = p [ l ] . x ;
                    p [ r ] . y = p [ l ] . y ;
                    p [ r ] . z = p [ l ] . z + 1 ;
                    p [ r ] . jn = 1 ;
                } else
                {
                    p [ r ] . x = p [ l ] . x - 1 ;
                    p [ r ] . y = p [ l ] . y ;
                    p [ r ] . z = p [ l ] . z + 1 ;
                    mp [ p [ r ] . x ] [ p [ r ] . y ] = 0 ;
                    p [ r ] . jn = 0 ;
                }
            }
            if ( pd_a ( p [ r ] . x , p [ r ] . y ) == true && p [ r ] . z < ans )
            {
                ans = p [ r ] . z ;
            }
        }
        if ( pd_b ( p [ l ] . x , p [ l ] . y + 1 ) == true )
        {
            r ++ ;
            if ( mp [ p [ l ] . x ] [ p [ l ] . y + 1 ] == 1 )
            {
                p [ r ] . x = p [ l ] . x ;
                p [ r ] . y = p [ l ] . y + 1 ;
                p [ r ] . z = p [ l ] . z + 1 ;
                p [ r ] . jn = p [ l ] . jn ;
                mp [ p [ r ] . x ] [ p [ r ] . y ] = 0 ;
            } else
            {
                if ( p [ l ] . jn == 0 )
                {
                    p [ r ] . x = p [ l ] . x ;
                    p [ r ] . y = p [ l ] . y ;
                    p [ r ] . z = p [ l ] . z + 1 ;
                    p [ r ] . jn = 1 ;
                } else
                {
                    p [ r ] . x = p [ l ] . x ;
                    p [ r ] . y = p [ l ] . y + 1 ;
                    p [ r ] . z = p [ l ] . z + 1 ;
                    mp [ p [ r ] . x ] [ p [ r ] . y ] = 0 ;
                    p [ r ] . jn = 0 ;
                }
            }
            if ( pd_a ( p [ r ] . x , p [ r ] . y ) == true && p [ r ] . z < ans )
            {
                ans = p [ r ] . z ;
            }
        }
        if ( pd_b ( p [ l ] . x , p [ l ] . y - 1 ) == true )
        {
            r ++ ;
            if ( mp [ p [ l ] . x ] [ p [ l ] . y - 1 ] == 1 )
            {
                p [ r ] . x = p [ l ] . x ;
                p [ r ] . y = p [ l ] . y - 1 ;
                p [ r ] . z = p [ l ] . z + 1 ;
                p [ r ] . jn = p [ l ] . jn ;
                mp [ p [ r ] . x ] [ p [ r ] . y ] = 0 ;
            } else
            {
                if ( p [ l ] . jn == 0 )
                {
                    p [ r ] . x = p [ l ] . x ;
                    p [ r ] . y = p [ l ] . y ;
                    p [ r ] . z = p [ l ] . z + 1 ;
                    p [ r ] . jn = 1 ;
                } else
                {
                    p [ r ] . x = p [ l ] . x ;
                    p [ r ] . y = p [ l ] . y - 1 ;
                    p [ r ] . z = p [ l ] . z + 1 ;
                    mp [ p [ r ] . x ] [ p [ r ] . y ] = 0 ;
                    p [ r ] . jn = 0 ;
                }
            }
            if ( pd_a ( p [ r ] . x , p [ r ] . y ) == true && p [ r ] . z < ans )
            {
                ans = p [ r ] . z ;
            }
        }
        l ++ ;
    }
    if ( ans == N * N * N ) cout << "You can't save Mengxin" ;//还有不能营救的情况
    else cout << ans ;
    return 0 ;
}

相关链接:

XJOI 题解小全:
https://blog.csdn.net/zj_mrz/article/details/80949787

XJOI 3330 Knight moving 骑士出行 题解:
https://blog.csdn.net/zj_mrz/article/details/81031135

XJOI 3393 序列 题解:
https://blog.csdn.net/zj_mrz/article/details/80948621

XJOI 3404 刷油漆 题解:
https://blog.csdn.net/zj_mrz/article/details/80949407

猜你喜欢

转载自blog.csdn.net/zj_mrz/article/details/81032429