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.
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”.
If you can save this guy,output the least time you cost,else,output “You can’t save Mengxin”
7 8
#.#####.
#.M#..@.
#..#G...
..#..#.#
#...##..
.#......
........
13
2 2
M.
G@
2
在一个n∗m的迷宫里,有一个萌新被困住了,你作为一个久经码场的战士,决定去营救萌新。地图中还会有一些守卫,你必须打败守卫才能通过守卫所在的位置,打败守卫需要花费1分钟,移动一步需要花费一分钟,每次你只能往上下左右某个方向移动一步。问你最少需要花费多少时间才能救到萌新。
第一行输入两个整数 n,m
接下来n行每行输入m个字符
‘#’代表障碍物,无法直接通过
‘.’代表空地,可以直接通过
‘G’代表守卫,你需要打败他才能通过
‘M’代表萌新所在的位置
‘@’表示你所在的位置
如果可以营救到萌新,就输出最少需要花费的分钟数
如果不可以,输出“You can’t save Mengxin”
7 8
#.#####.
#.M#..@.
#..#G...
..#..#.#
#...##..
.#......
........
13
2 2
M.
G@
2
1<=n,m<=200
以上输入样例中,用到的代码片不是代码,只是为了方便表示,谢谢。
这道题求的是最优解,很容易就想到广度优先搜索(又称宽度优先搜,BFS),最先在队列里遇到的答案一定就是最优解了。广度优先搜索用队列实现,用队列的left来扩展right来维持搜索。但还有一些小困难,比如打败守卫要1分钟的问题。如何解决呢?我们可以假设我们去营救她时,拥有一个技能可以秒杀有守卫,这个技能要蓄力1分钟,这是不是好理解一些呢?如果单纯的认为经过守卫的点耗时2min,博主认为第一个扫到的终点不一定是最优解(个人观点,未经尝试)。请看代码中的注解吧。具体代码如下:
#include
#include
#include
#include
#include
#include
#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