题解:AT_abc170_f [ABC170F] Pond Skater

目录

前言

题面

题意

算法

解法

输入存放

广度优先搜索实现

初始化

广度优先搜索主体

扩展

优化

代码

评测


前言

第一次手切蓝题,十分高兴,写个题解纪念一下。

更好的阅读环境:题解:AT_abc170_f [ABC170F] Pond Skater - 洛谷专栏

题面

你在一个划分为上下 H 行,左右 W 列的长方形网格中,网格从上到下的第 i 行的从左往右第 j 列被编号为 (i,j) ,如果 ci,j​ 为 @ ,则 (i,j) 不能通过。

你现在在 (x1​,y1​),你每步可以往上下左右走 1 至 K 格,问你最少需要多少步才能走到 (x2​,y2​) ,如果不能走到,输出 −1 。

输入先是一行三个整数 H,W,K ,再是一行四个整数 x1​,y1​,x2​,y2​,接着是 H×W 的字符矩阵,第 i 行 j 列表示 ci,j​ 。

题意

给你一个 h 行 w 列的地图 mp,如果 mpi,j​ 是障碍物,即 mpi,j​ 是 @,我们就不能通过 mpi,j​ ,反之可以通过。你现在在 mpx1,y1​,要走到 mpx2,y2​,问至少需要几个步骤。在一个步骤内,你可以上下左右移动 1 至 k 个格子。

算法

广度优先搜索和优化。

解法

输入存放

我们可以用一个数据结构存放地图,由于1≤h,w≤106,所以数组存不下。因此,我们考虑使用 vector 或 map。

广度优先搜索实现

初始化

我们可以用一个队列 q 维护待扩展的状态。我们将 (x1,y1) 入队。再定义一个名为 vis 的 vector,用来存放走每个点所需要的步骤。将 visx1,y1​ 设为 1。 为什么是 1 而不是 0 呢?因为 vis 不仅起到存放步骤的作用,还能用来判定一个点是否走过,如果你把 visx1,y1​ 设为 0,那么程序就会断定位置 (x1,y1) 没有被走过。由于 visx1,y1​ 是 1,我们在输出答案 visx2,y2​ 时要减去一。

广度优先搜索主体

如何广度优先搜索我在这里就不陈述了,几乎就是个板子。我来说一下重要的部分。

扩展

题目的特殊性质在于你一次可以走很多步,我们可以用一个循环枚举走 1 步至走 k 步的情况,一一扩展。

优化

如果你现在想访问的点已经被访问过了,且走到此点的步数比你现在走到此点所需要的步数要少,就直接 break 掉。这个步骤被称为剪枝。

代码

#include<bits/stdc++.h>
using namespace std;
long long h,w,k,xs,ys,xf,yf,dx[]={0,0,1,-1},dy[]={1,-1,0,0};
char iin;
vector<char> mp[1100000];
vector<long long> vis[1100000];
struct node{
	long long x,y;
};
void bfs(){
	queue<node> q;
	q.push({xs,ys});
	vis[xs][ys]=1;
	while(!q.empty()){
		node cur=q.front();
		q.pop();
		for(int i=0;i<=3;i++){
			for(int j=1;j<=k;j++){
				node nxt;
				nxt.x=cur.x+dx[i]*j;
				nxt.y=cur.y+dy[i]*j;
				if(nxt.x<1||nxt.x>h||nxt.y<1||nxt.y>w||mp[nxt.x][nxt.y]!='.'){
					break;
				}
				if(vis[nxt.x][nxt.y]&&vis[cur.x][cur.y]>=vis[nxt.x][nxt.y]){
					break;
				}
				if(vis[nxt.x][nxt.y]){
					continue;
				}
				vis[nxt.x][nxt.y]=1;
				vis[nxt.x][nxt.y]=vis[cur.x][cur.y]+1;
				q.push({nxt.x,nxt.y});
			}
		}
	}
	if(vis[xf][yf]){
		cout<<vis[xf][yf]-1;
	}else{
		cout<<-1;
	}
}
int main(){
    ios::sync_with_stdio(false);
    cin>>h>>w>>k>>xs>>ys>>xf>>yf;
    for(int i=1;i<=h;i++){
    	mp[i].push_back('!');
    	vis[i].push_back(0);
    	for(int j=1;j<=w;j++){
    		cin>>iin;
    		mp[i].push_back(iin);
    		vis[i].push_back(0);
		}
	}
	bfs();
    return 0;
}

评测

请到 AT_abc170_f [ABC170F] Pond Skater - 洛谷 或 F - Pond Skater 评测。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值