【题解】P9860 [CCC 2008 S3] Maze

题目描述

为了赚点钱,你决定参与一个科学实验。你会被喂很多披萨,然后再吃更多的披萨,接着你需要骑着一辆仅靠披萨驱动的滑板车穿越城市。当然,城市里有很多交叉路口,这些路口受到严格控制。有些路口是禁止进入的;有些只允许你在离开路口时向北或向南移动;有些只允许你在离开路口时向东或向西移动;剩下的则允许你朝任意方向(北、南、东或西)移动。

幸运的是,你的科学朋友给了你一张城市地图(在一个披萨盒的背面),上面用一些符号表示你可以如何在城市中移动。具体来说,盒子上有 4 种不同的符号:

  • 符号 + 表示我们可以从这个位置向任意方向(北/南/东/西)移动。
  • 符号 - 表示我们只能从这个位置向东或向西移动。
  • 符号 | 表示我们只能从这个位置向北或向南移动。
  • 符号 * 表示我们不能占据这个位置。

你的任务是确定从城市的西北角移动到东南角需要经过多少个交叉路口。

输入格式

输入以一个数字 t(1≤t≤10)t (1 \leq t \leq 10)t(1t10) 开始,单独占一行,表示文件中包含多少个不同的测试用例。每个测试用例以一个数字 rrr 开始,接下来一行是一个数字 ccc,其中 (1≤r,c≤20)(1 \leq r, c \leq 20)(1r,c20)。接下来的 rrr 行包含 ccc 个字符,其中每个字符是 {+, *, -, |} 中的一个。你可以假设城市的西北角可以被占据(即,它不会被标记为 *)。

输出格式

输出将有 ttt 行,每行一个整数。第 i(1≤i≤t)i (1 \leq i \leq t)i(1it) 行的整数表示从城市的西北角移动到东南角所需经过的最少交叉路口数。如果无法从西北角到达东南角,则对该测试用例输出 −1-11

输入输出样例 #1

输入 #1

3
2
2
-|
*+
3
5
+||*+
+++|+
**--+
2
3
+*+
+*+

输出 #1

3
7
-1

题目解析

阅读完题目可知题目要求的是:从起点(1,1)到终点(r,c)的最短路。且在迷宫中,可视为边权为1,也就是一个单源的无权最短路问题。那么我们可以采用BFS来解决这个问题。

BFS求最短路框架

void bfs(int sx,int sy){//从(sx,sy)出发
	queue<node> q;
	q.push(node{sx,sy});//起点入队
	vis[sx][sy]=1;//标记起点
	ans[sx][sy]=1;//记录起点的最短步数
	while(!q.empty()){//循环直到队列为空
		node cur=q.front();
		q.pop();
		for(int i=L;i<R;i++){//遍历邻接点
			int nx=cur.x+dx[i],ny=cur.y+dy[i];//计算下一步位置
			if(!check(nx,ny)) continue;//不能到达的位置跳过
			vis[nx][ny]=1;
			ans[nx][ny]=ans[cur.x][cur.y]+1;//更新最短路
			q.push(node{nx,ny});
		}
	}
}

需要注意本题的行走方式,在*不能行走,+上下左右都可以,-只能左右,|只能上下。那么我们需要根据不同情况处理不同的行走方式。并且注意起点部分为的最短路为1.

完整代码

#include <bits/stdc++.h>
using namespace std;
struct node{
	int x,y;
};
int r,c;
char a[25][25];
int ans[25][25];
bool vis[25][25];
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};
void bfs(int sx,int sy){//从(sx,sy)出发
	queue<node> q;
	q.push(node{sx,sy});
	vis[sx][sy]=1;//起点入队
	ans[sx][sy]=1;//记录起点的最短步数
	while(!q.empty()){//循环直到队列为空
		node cur=q.front();
		q.pop();
		int L=0,R=0;
		if(a[cur.x][cur.y]=='+'){
			L=0;R=4;
		}else if(a[cur.x][cur.y]=='-'){
			L=2;R=4;
		}else if(a[cur.x][cur.y]=='|'){
			L=0;R=2;
		}
		for(int i=L;i<R;i++){//遍历邻接点
			int nx=cur.x+dx[i],ny=cur.y+dy[i];//计算下一步位置
			//不能到达的位置跳过
			if(nx<1||nx>r||ny<1||ny>c) continue;
			if(vis[nx][ny]||a[nx][ny]=='*') continue;
			vis[nx][ny]=1;
			ans[nx][ny]=ans[cur.x][cur.y]+1;//更新最短路
			q.push(node{nx,ny});
		}
	}
}
int main(){
	int t;
	cin>>t;
	while(t--){
    //注意多组数据清空
		memset(ans,-1,sizeof(ans));
		memset(vis,0,sizeof(vis));
		memset(a,0,sizeof(a));
		cin>>r>>c;
		for(int i=1;i<=r;i++){
			for(int j=1;j<=c;j++){
				cin>>a[i][j];
			}
		}
		bfs(1,1);
		cout<<ans[r][c]<<endl;
	}
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值