穿越雷区[蓝桥杯 2015 国 AC] (BFS)(c++)

题目描述

X 星的坦克战车很奇怪,它必须交替地穿越正能量辐射区和负能量辐射区才能保持正常运转,否则将报废。

某坦克需要从 A 区到 B 区去(A,B 区本身是安全区,没有正能量或负能量特征),怎样走才能路径最短?

已知的地图是一个方阵,上面用字母标出了 A,B 区,其它区都标了正号或负号分别表示正负能量辐射区。

例如:

A + - + -
- + - - +
- + + + -
+ - + - +
B + - + -

坦克车只能水平或垂直方向上移动到相邻的区。

输入格式

输入第一行是一个整数 n,表示方阵的大小,4≤n<100。

接下来是 n 行,每行有 n 个数据,可能是 AB+- 中的某一个,中间用空格分开。

输出格式

要求输出一个整数,表示坦克从 A 区到 B 区的最少移动步数。

如果没有方案,则输出 −1。
 

最短路径问题,恒容易想到使用宽度优先BFS来完成

我们先定义如下一些变量,其中nex数组相当于向量,能更方便地表示下一步的前后左右四个方向

const int N = 110;
int a[N][N],n;//数组a表示地图 
int nex[4][2]={{1,0},{-1,0},{0,1},{0,-1}};//向量,表示下一步的四个方向 
pair<int,int>st,ed;//st记录点A的位置,ed记录B的位置 
int vis[N][N];//记录点(i,j)是否走过; 

为了更方便地表示每一个点离A点的距离,我们用cnt表示距离,并定义一个结构体,其中x,y表示坐标。

struct node
{
	int x,y,cnt;
};

下面先给出主函数

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			char x;
			cin>>x;
			if(x=='A')
			{
				st.first=i;
				st.second=j;
				a[i][j]=-1;//起始点和终点赋值-1 
			}
			else if(x=='B')
			{
				ed.first=i;
				ed.second=j;
				a[i][j]=-1;//起始点和终点赋值-1	
			}
			else if(x=='+')
			{
				a[i][j]=1;//“+”赋值1	
			}	
			else	a[i][j]=0;//“-”赋值0
		}
	}
	cout<<bfs(st.first,st.second)<<'\n';
	return 0;
}

我们先定义一个函数check,来判断这个点是否出界了,或者是否已经走过了
 

bool check(int x,int y)
{
	if(x<1||x>n||y<1||y>n||vis[x][y]==1)	return false;//如果出界或者走过了 
	else	return true;
} 

下面就是bfs函数啦,已经在代码中详细地写了注释

int bfs(int x,int y)
{
	queue<node>que;//定义一个存放结构体node的队列que 
	que.push(node{x,y,0});//队尾(事实上就是第一个,因为此时是空的)存放该点(本题是A点)的坐标以及距离 
	vis[x][y]=1;//表示该点(本题中是A点)已经走过了 
	while(!que.empty())//如果队列不空 
	{
		node u = que.front();//让u的值等于队列第一个元素的值,队列元素不变 
		if(u.x==ed.first&&u.y==ed.second)	return u.cnt;//如果走到了B点,直接输出此时的距离 
		que.pop();//移除队首的元素
		int x = u.x,y = u.y;
		for(int i=0;i<=3;i++)//这里表示四种方向 
		{
			int tx = x+nex[i][0];//下一个点的x坐标 
			int ty = y+nex[i][1];//下一个点的y坐标 
			if(!check(tx,ty)||a[tx][ty]==a[x][y])	continue;//如果出界或走过或者下一个点的磁场和上一个一样 
			vis[tx][ty]=1;//记录该点走过了 
			que.push(node{tx,ty,u.cnt+1});//将这个点放进队列 
		}
		 
	}
	return -1;
}

完整代码如下

#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int a[N][N],n;//数组a表示地图 
int nex[4][2]={{1,0},{-1,0},{0,1},{0,-1}};//向量,表示下一步的四个方向 
pair<int,int>st,ed;//st记录点A的位置,ed记录B的位置 
int vis[N][N];//记录点(i,j)是否走过; 
struct node
{
	int x,y,cnt;
};
bool check(int x,int y)
{
	if(x<1||x>n||y<1||y>n||vis[x][y]==1)	return false;//如果出界或者走过了 
	else	return true;
} 

int bfs(int x,int y)
{
	queue<node>que;//定义一个存放结构体node的队列que 
	que.push(node{x,y,0});//队尾(事实上就是第一个,因为此时是空的)存放该点(本题是A点)的坐标以及距离 
	vis[x][y]=1;//表示该点(本题中是A点)已经走过了 
	while(!que.empty())//如果队列不空 
	{
		node u = que.front();//让u的值等于队列第一个元素的值,队列元素不变 
		if(u.x==ed.first&&u.y==ed.second)	return u.cnt;//如果走到了B点,直接输出此时的距离 
		que.pop();//移除队首的元素
		int x = u.x,y = u.y;
		for(int i=0;i<=3;i++)//这里表示四种方向 
		{
			int tx = x+nex[i][0];//下一个点的x坐标 
			int ty = y+nex[i][1];//下一个点的y坐标 
			if(!check(tx,ty)||a[tx][ty]==a[x][y])	continue;//如果出界或走过或者下一个点的磁场和上一个一样 
			vis[tx][ty]=1;//记录该点走过了 
			que.push(node{tx,ty,u.cnt+1});//将这个点放进队列 
		}
		 
	}
	return -1;
}

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			char x;
			cin>>x;
			if(x=='A')
			{
				st.first=i;
				st.second=j;
				a[i][j]=-1;//起始点和终点赋值-1 
			}
			else if(x=='B')
			{
				ed.first=i;
				ed.second=j;
				a[i][j]=-1;//起始点和终点赋值-1	
			}
			else if(x=='+')
			{
				a[i][j]=1;//“+”赋值1	
			}	
			else	a[i][j]=0;//“-”赋值0
		}
	}
	cout<<bfs(st.first,st.second)<<'\n';
	return 0;
}

  • 18
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值