优先队列+bfs why的吃鸡

链接:登录—专业IT笔试面试备考平台_牛客网
题目描述:

 

与普通的dfs的区别就是,它的移动速度是不定的,所以我们不能使用单纯的queue,而可以使用优先队列,因为队列存在的意义,就是要让各个能走的点,以到起点的时间(不是距离,因为速度不定)升序依次处理,那么就应该使用优先队列,来保证队列输出的顺序,是以时间为标准的。

这是第一代代码:

#include<bits/stdc++.h>
using namespace std;
int t,n,k;
struct ty{
	int x,y,step;
	bool operator<(const ty& s)const{
		return step>s.step;
	}
};
bool vis[310][310];
ty star,ed;
int dir[][4]={{1,0},{-1,0},{0,1},{0,-1}};
char mas[310][310];
bool inmap(int x,int y){
	return x>=0&&y>=0&&x<n&&y<n;
}
void bfs(){
	memset(vis,0,sizeof(vis));
	priority_queue<ty> q;
	q.push(star);
	vis[star.x][star.y]=1;
	while(!q.empty()){
		ty t=q.top();
		q.pop();
		int x=t.x,y=t.y;
		if(mas[x][y]=='X'&&t.step<=k) {cout<<"YES"<<endl<<t.step<<endl;return;}
		for(int i=0;i<4;++i){
			int xx=x+dir[i][0];
			int yy=y+dir[i][1];
			if(inmap(xx,yy)&&!vis[xx][yy]&&mas[xx][yy]!='#'){
                if(mas[xx][yy]=='C'){
                    vis[xx][yy]=1;
				q.push({xx,yy,t.step+1});	
                }
				else{
                    vis[xx][yy]=1;
				q.push({xx,yy,t.step+2});	
                }	
			}
		}

	} 
	cout<<"NO"<<endl;
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>t;
	while(t--){
        cin>>n>>k;
		for(int i=0;i<n;++i){
			for(int j=0;j<n;++j){
				cin>>mas[i][j];
				if(mas[i][j]=='S') star={i,j};
				if(mas[i][j]=='X') ed={i,j};
			}
		}

		bfs();
	}
	return 0;
}

 它wa了。。。

其实还有一个问题我们没有考虑。因为对于每个点,我们其实有两种状态,即:它是我们走过来的,或者它是我们开车过来的,这其实是可以同时存在的,因为我们的速度并非一成不变,我们完全可以先走着经过这里,拿到车之后再开过这里,虽然一个点踩了2次,但之后的路我们却有了更快的速度。当然,如果我们是开着车两次经过同一个点,那肯定还是没有必要的。所以这里的vis数组,我们应该多开一维,记录点的同时,也要记录来时的状态,是开车还是走路,当然也可以直接用速度来记录,后面也方便直接计算时间。

AC代码:

#include<bits/stdc++.h>
using namespace std;
int t,n,k;
struct ty{
	int x,y,sp;
    long long step;
	bool operator<(const ty& s)const{
		return step>s.step;
	}
};
bool vis[310][310][3];
ty star,ed;
int dir[][4]={{1,0},{-1,0},{0,1},{0,-1}};
char mas[110][110];
bool inmap(int x,int y){
	return x>=0&&y>=0&&x<n&&y<n;
}
void bfs(){
	memset(vis,0,sizeof(vis));
	priority_queue<ty> q;
	q.push(star);
	vis[star.x][star.y][star.sp]=1;
	while(!q.empty()){
		ty t=q.top();
		q.pop();
		int x=t.x,y=t.y,z=t.sp;
		if(mas[x][y]=='X'&&t.step<=k) {cout<<"YES"<<endl<<t.step<<endl;return;}
		for(int i=0;i<4;++i){
			int xx=x+dir[i][0];
			int yy=y+dir[i][1];
			int zz=z;
			int step=t.step;
			//if(mas[xx][yy]=='C') zz=1;
			if(mas[xx][yy]!='O'&&!vis[xx][yy][zz]&&inmap(xx,yy)){
				vis[xx][yy][zz]=1;
				step+=z;
				if(mas[xx][yy]=='C') zz=1;
				q.push({xx,yy,zz,step});
			}
		}
	} 
	cout<<"NO"<<endl;
	return;
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>t;
	while(t--){
        cin>>n>>k;
		for(int i=0;i<n;++i){
			for(int j=0;j<n;++j){
				cin>>mas[i][j];
				if(mas[i][j]=='S') star={i,j,2,0};
			}
		}
		bfs();
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值