夏日漫步(简单bfs)

码题集OJ-夏日漫步 (matiji.net)

简单的bfs,就是相同的亮度的砖块可以直接瞬移到下一块,这是和经典bfs的不同之处,如何处理相同亮度的砖块作为下一步的移动目的地成为这道题的关键点。在这一点上,我用了一个vector数组存储相同亮度的砖块,然后在读取存储的vector去写入ne数组,ne数组代表当前下标可以移动到的下一个相同亮度砖块的下标。我的第六感告诉我应该可以不用vector容器也可以表示,但暂时我没想到。今天太晚了,室友要睡觉了,只能明天再想了。

评论区有佬给出了答案,大家快去夸夸他。

#include<iostream>
#include<queue>
#include<vector>
using namespace std;
const int N=2e5+5;
const int M=1e6+5;
int n;
int arr[N],dist[N];
bool st[N];
vector<int>u[M];
//ne数组存储的key是一个下标,value是可以移动到相同亮度的下一个砖块的下标
int ne[N];
int bfs() {
	queue<int>q;
	q.push(1);
	st[1]=true;
	dist[1]=0;
	while(q.size()) {
		int t=q.front();
		q.pop();
		if(t==n) {
			return dist[t];
		}
		if(t-1>=1&&!st[t-1]) {
			q.push(t-1);
			st[t-1]=true;
			dist[t-1]=dist[t]+1;
		}
		if(!st[t+1]) {
			q.push(t+1);
			st[t+1]=true;
			dist[t+1]=dist[t]+1;
		}
		if(ne[t]&&!st[ne[t]]) {
			q.push(ne[t]);
			st[ne[t]]=true;
			dist[ne[t]]=dist[t]+1;
		}
	}
}
int main(void) {
	scanf("%d",&n);
	for(int i=1; i<=n; i++) {
		scanf("%d",&arr[i]);
		u[arr[i]].push_back(i);
	}
	for(int i=0; i<=M; i++) {
		if(u[i].size()==0)continue;
		int first=u[i][0];
		for(int j=1; j<u[i].size(); j++) {
			ne[first]=u[i][j];
			first=u[i][j];
		}
	}
	printf("%d",bfs());
	return 0;
}

首先,代码定义了一些常量和全局变量,包括数组arrdiststune,分别表示节点的值、节点间的距离、节点的访问状态、每个值的索引数组和下一个节点的索引。

bfs()函数中,代码通过BFS算法遍历图并计算从节点1到节点n的最短距离。具体来说,代码首先将节点1添加到队列中,并设置其访问状态为true,距离为0。然后,代码开始循环,每次从队列中取出一个节点t,并检查其是否等于n,如果是,则返回其距离。否则,代码检查t-1、t+1和ne[t]是否未被访问过,如果未访问过,则将它们添加到队列中,并更新它们的访问状态和距离。

main()函数中,代码首先读取节点数n和每个节点的值arr[i],然后将每个值的索引添加到对应的数组u中。接着,代码遍历数组u,对于每个值,如果存在多个索引,则设置第一个索引的下一个索引为第二个索引,第二个索引的下一个索引为第三个索引,以此类推。最后,代码调用bfs()函数并输出计算结果。

总的来说,这段代码实现了一个BFS算法来解决图的最短路径问题,适用于节点间只有三种可能的连接情况:前一个节点、后一个节点和同一个值的其他节点。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值