BOJ 1433 Tom 的潜望镜 优先队列+BFS

Description

    Tom和Jerry这对活宝最近又开始闹腾了,为了和Jerry斗智斗勇,Tom特地到北邮物理系学习光学的知识,通过自己的不懈努力,他终于学会了潜望镜的制作。学业期满后,他决定和Jerry来一次比赛,在比赛之前,我们先来看看潜望镜的相关知识:

    上图就是一个简单的潜望镜,光线经过镜面反射后转过90度射出。于是如图的潜望镜可以使上下两个孔互相看见。
    Tom和Jerry比赛在一个n*m的迷宫内进行,Tom在迷宫的A位置,Jerry在迷宫的B位置,Tom希望利用潜望镜原理安装一些镜子找到Jerry。如下图所示:

. . . . . . .       . . . . . . .
. . . . . . J       . . . . . /-J
. . . . . . *       . . . . . | *
* * * * * . *       * * * * * | *
. . . . * . .       . . . . * | .
. . . . * . .       . . . . * | .
. T . . * . .       . T . . * | .
. . . . . . .       . \-------/ .
    图1                  图2

    迷宫中 ‘*’代表墙,’.’代表可以到达。在右边地图中,Tom在安装了3个镜子(/或\代表镜子)后就可以找到Jerry。现在Tom告诉你地图的信息,他希望你帮助他用最少的镜子找到Jerry。



Input

多组数据测试,输入的第一行是一个正整数t(1 <= t <= 20),表示有t组测试数据。


对于每组测试数据,第一行是两个正整数m,n(1 <= n, m <= 100),表示地图由m列n行组成。接下来有n行,第i行代表着地图的第i行。地图有’.’ , ’*’ , ‘T’ , ‘J’组成。’T’代表Tom的位置,’J’代表Jerry的位置。




Output
对于每组数据,输出Tom最少需要多少个镜子才能找到Jerry。数据保证Tom一定可以找到Jerry。

Sample Input

1
7 8
.......
......J
......*
*****.*
....*..
....*..
.T..*..
.......


Sample Output

3


和普通的走迷宫相同的地方是:对每个点,有四个方向可以走,所以BFS去找。

不同的地方:是找转弯最少的路径,所有BFS的时候用优先队列,每个点结构有一个转弯次数作为优先队列的优先值。

注意对每个点,有四个方向,但是不只是push四个点进去,是四个方向可以到达的所有的点都一起push进队列。

代码里把vis矩阵故意设置成int型是为了调试的时候方便检查每个点的level值。

可以在输出结果里面输出看看vis的值就很容易明白。



#include<iostream>
#include<queue>
using namespace std;
const int N=105;
int row,col;
char mat[N][N];
int sx,sy;
int ex,ey;
int movx[4]={0,0,-1,1};
int movy[4]={-1,1,0,0};
int vis[N][N];
bool inmat(int x,int y)
{
	if(x>=0&&y>=0&&x<col&&y<row&&mat[y][x]!='*'&&!vis[y][x])
		return true;
	return false;
}

struct Point
{
	int x,y;
	int level;
	Point(int a,int b,int l)
	{
		x=a;
		y=b;
		level=l;
	}
	friend bool operator < (const  Point &a,const  Point &b)
	{
		return a.level>b.level;
	}
};

void bfs()
{
	priority_queue<Point> que;
	que.push(Point(sx,sy,1));
	vis[sy][sx]=1;
	while(!que.empty())
	{
		Point now=que.top();
		if(now.x==ex&&now.y==ey)
		{
			printf("%d\n",now.level-2);
			/*for(int i=0;i<row;i++)
			{
				for(int j=0;j<col;j++)
				{
					printf("%d ",vis[i][j]);
				}
				printf("\n");
			}
			return ;*///这里把vis矩阵故意设置成int型是为了调试的时候方便检查每个点的level值。
		}
		que.pop();
		for(int i=0;i<4;i++)
		{
			int nx=now.x+movx[i];
			int ny=now.y+movy[i];
			while(inmat(nx,ny))
			{
				que.push(Point(nx,ny,now.level+1));
				vis[ny][nx]=now.level+1;
				nx+=movx[i];
				ny+=movy[i];
			}
		}
	}

}
int main()
{
	
	int cases;
	scanf("%d",&cases);
	while(cases--)
	{
		memset(vis,0,sizeof(vis));
		scanf("%d%d",&col,&row);
		for(int i=0;i<row;i++)
		{
			scanf("%s",mat[i]);
			for(int j=0;j<col;j++)
			{
				if(mat[i][j]=='T')
				{
					sx=j;
					sy=i;
				}
				else if(mat[i][j]=='J')
				{
					ex=j;
					ey=i;
				}
			}
		}
		bfs();
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值