AcWing 2019. 拖拉机 双端队列+最短路

  1. 要求需要移除的干草捆的最小数量,我们把有障碍的地方当作权值是1,没有的地方是0,则此题可以转化为求最短路
  2. 地图中只有0和1的最短路可以用双端队列deque做,其中到的点权值为0就放入队头,为1就放入队尾。则每次取出的队头都是权值最小的情况
  3. 用st表示这个点的最短路是否已经确定。若没确定,当它第一次从队列中取出(front),它的最短路就确定了
  4. 注意边界:(0,0)是终点,而障碍只会出现在[1,1000]范围内,则我们把bfs的范围取到[0,1001]。((0,0)是一定要在范围内的,不然无法遍历,由于多加了一个点,所以我们把范围取到1001相当于再扩大一圈无障碍的范围
  5. 要存最短路的值,有变小才更新和放入队列
  6. 注意,把起点放入队列时不要st[x][y]=1,否则会遍历不到这个起点,答案就是初始化时的最大值。
/*
把有障碍当作该点权值为1,则此题可以转化为最短路问题
用双端队列进行bfs 
要存下到某个点的最小权值 
*/ 
#include<bits/stdc++.h>
using namespace std;
#define fir(i,a,n) for(int i=a;i<=n;i++)
#define mem(a,x) memset(a,x,sizeof(a));
typedef long long ll;
const int N=1e3+10;
int g[N][N];
int n,x,y;
int ans;
struct node
{
	int x,y;	
};
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
int d[N][N];
int st[N][N];//表示是否已经确定最小值 
void bfs()
{
	mem(d,0x3f);
	deque<node>q;
	q.push_back({x,y});
//	st[x][y]=1;
	d[x][y]=0;
	while(q.size())
	{
		node t=q.front();
		q.pop_front();
		if(st[t.x][t.y]) continue;
		st[t.x][t.y]=1;//取到它说明它是0,或者是第一个1,反正是当前最小的 
	//	cout<<t.x<<" "<<t.y<<endl;	
		if(t.x==0&&t.y==0) break;
		
		for(int i=0;i<4;i++)
		{
			int xx=t.x+dx[i];
			int yy=t.y+dy[i];
						
			if(xx>=0&&xx<=1001&&yy>=0&&yy<=1001)//界是1000 
			{								 			
				int w=g[xx][yy];
				if(d[xx][yy]>d[t.x][t.y]+w)
				{
					d[xx][yy]=d[t.x][t.y]+w;
					if(w) q.push_back({xx,yy});
					else q.push_front({xx,yy});
				}
			}
		}
	}
	ans=min(ans,d[0][0]);
}
int main()
{
	cin>>n>>x>>y;
	while(n--)
	{
		int a,b;cin>>a>>b;
		g[a][b]=1;//有障碍,则权值为1 		
	}
	ans=INT_MAX;
	//cout<<nn<<" "<<mm;
	bfs();
	cout<<ans;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

karshey

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值