有关01bfs的一些想法

01bfs,也就是说,对于遍历到的每一个点,有两种选择,0和1,可以是消耗的能量为0和消耗的能量不为0(1、2、3。。。都可以,只要存在),那么当我们遍历图来寻找最短路时,应该选择将消耗能量为0的方向放在队首,然后让有能量消耗的方向放在队尾(用双向队列),保证先遍历不消耗能量的方向,因为其与该点的距离相当于为0,这样就保证了队列取出顺序始终为距起点距离的升序。

Ocean Currents:

登录—专业IT笔试面试备考平台_牛客网

对于在一大片水域上航行的船只来说,强烈的水流可能是危险的,但如果经过仔细的规划,它们会变得危险

可以被用来帮助船到达目的地。你的工作就是帮助制定计划。

在每个位置,电流都流向某个方向。机长可以选择要么跟着船走

电流的流动,不使用能量,或以一个正方形为代价向任何其他方向移动

能源单位。船总是朝以下八个方向之一移动:北、南、东、西,

东北、西北、东南、西南。船不能离开湖边。

你要帮助他制定一个策略,以最低的能耗到达目的地。

湖泊被表示为矩形网格。输入的第一行包含两个整数r和c

网格中的行数和列数。网格的行数不超过1000行,也不超过1000行

柱。以下r行中的每一行都包含c字符,每个字符都是0到7(含0到7)之间的数字。

字符“0”表示电流向北流动(即在网格中向上流动,方向为下降

行数),“1”表示流向东北,“2”表示流向东(即向列增加的方向)

数字),“3”表示东南方向,顺时针方向依次类推:

7 0 1

\|/

6-*-2

/|\

5 4 3

几个细节:

一是要用双向队列

二:

对于每个点,它应该是要可以走过多次的,来保证其到起点的最短距离能够更新,所以01bfs不需要vis数组。

                                       A           

                       B                               C

这里有AB C三个点,假设B、C的距离都是5,B到A的能量是1,C到A的能量为0,如果不巧是先从B开始走那么A的距离就会是6,如果我们又不巧建了个vis,把A点标记掉了,那么A的距离就定死了,但其实C到A的距离只有5,A的距离应该是要更新的。所以在01bfs里面,我们不需要vis。

代码:


#include<bits/stdc++.h>
using namespace std;
#define ll long long
int r,c,n;
int dis[1010][1010];
int vis[1010][1010];
char mass[1010][1010];
int mas[1010][1010];
int dir[8][2] = {{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}};
bool inmap(int x,int y){
	return x&&y&&x<=r&&y<=c;
}
void bfs(int x1,int y1,int x2,int y2){
	memset(dis,0x3f3f,sizeof(dis));
	memset(vis,0,sizeof vis);
	deque<pair<int,int>> q;
	while(q.size()) q.pop_front();
	q.push_front(make_pair(x1,y1));
	dis[x1][y1]=0;
	vis[x1][y1]=1;
	while(!q.empty()){
		int x=q.front().first;
		int y=q.front().second;
		q.pop_front();
		//if(x==x2&&y==y2){cout<<dis[x][y]<<endl;return;}
		
//		=================================================
		for(int i=0;i<8;++i){
			int xx=x+dir[i][0];
			int yy=y+dir[i][1];
			if(inmap(xx,yy)&&!vis[xx][yy]) {
				int add = (i != mas[x][y]);
				if(dis[xx][yy]>dis[x][y]+add){
                dis[xx][yy] = dis[x][y]  +add;
                //vis[xx][yy]=1;
                if(add) q.push_back(make_pair(xx,yy));
                else q.push_front(make_pair(xx,yy));
            }
//            ========================================================
//				if(i=='mas[x][y]'){
//					q.push_front(make_pair(xx,yy));
//					dis[xx][yy]=dis[x][y]; 
//				}
//				else{
//					q.push_back(make_pair(xx,yy));
//					dis[xx][yy]=dis[x][y]+1;
//				}
			}
		}
	}
	cout<<dis[x2][y2]<<endl;
	//cout<<(dis[x2][y2]?dis[x2][y2]-1:0)<<endl;
	return;
}
int main()
{
	cin>>r>>c;
	for(int i=1;i<=r;++i){
		cin>>mass[i]+1;
	}
	for(int i=1;i<=r;++i){
		for(int j=1;j<=c;++j){
			mas[i][j]=mass[i][j]-'0';
		}
	}
	cin>>n;
	for(int i=1;i<=n;++i){
		int a,b,c,d;
		cin>>a>>b>>c>>d;
		bfs(a,b,c,d);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值