拖拉机(双端队列的广搜)——USACO 2012 March Contest Silver Division

该博客介绍了如何利用双端队列进行广度优先搜索来解决一个数学问题:农夫约翰需要移除最少数量的干草堆以将拖拉机开到二维平面的原点。输入包括干草堆的数量和位置,以及拖拉机的初始位置。通过算法,可以找到移除干草堆的最小数量。此问题转化为图中只有边权为0和1的最短路径问题,双端队列有助于优化搜索过程。
摘要由CSDN通过智能技术生成

拖拉机

干了一整天的活,农夫约翰完全忘记了他把拖拉机落在田地中央了。

他的奶牛非常调皮,决定对约翰来场恶作剧。

她们在田地的不同地方放了 N 捆干草,这样一来,约翰想要开走拖拉机就必须先移除一些干草捆。

拖拉机的位置以及 N 捆干草的位置都是二维平面上的整数坐标点。

拖拉机的初始位置上没有干草捆。

当约翰驾驶拖拉机时,他只能沿平行于坐标轴的方向(北,南,东和西)移动拖拉机,并且拖拉机必须每次移动整数距离。

例如,驾驶拖拉机先向北移动 2 单位长度,然后向东移动 3 单位长度。

拖拉机无法移动到干草捆占据的位置。

请帮助约翰确定他需要移除的干草捆的最小数量,以便他能够将拖拉机开到二维平面的原点。

输入格式
第一行包含三个整数:N 以及拖拉机的初始位置 (x,y)。

接下来 N 行,每行包含一个干草捆的位置坐标 (x,y)。

输出格式
输出约翰需要移除的干草捆的最小数量。

数据范围
1≤N≤50000,
1≤x,y≤1000
输入样例:
7 6 3
6 2
5 2
4 3
2 1
7 3
5 4
6 4
输出样例:
1

题解

双端队列的广搜解决图中只有边权为0,和边权为1的最短路问题

假设:如果需要移动干草堆,那么边权为1,如果不需要移动干草堆那么边权为0

双端队列操作:每次取出队头,并拓展可以到达的点,并做判断如下

  • 如果这个点有干草堆,边权为1,并且被取出的点更新过的话,就把这个点加入队尾(可继续更新)
  • 如果这个点没有干草堆,边权为0,并且被取出的点更新过的话,把这个点加入队头(可继续更新)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <deque>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
const int N = 1005;
int dist[N][N];
bool g[N][N],st[N][N];
deque<PII> q;
int nextt[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};

int bfs(int sx,int sy)
{
    memset(dist,0x3f,sizeof dist);
    dist[sx][sy]=0;
    deque<PII> q;
    q.push_back({sx,sy});
    while(q.size()){
        auto t = q.front(); q.pop_front();
        for(int i=0; i<4; ++i){
            int nx = t.x+nextt[i][0], ny = t.y+nextt[i][1];
            if(nx<0 || nx>=N || ny<0 || ny>=N) continue;
            int w=0;
            if(g[nx][ny]) w=1;
            if(dist[nx][ny] > dist[t.x][t.y]+w){
                dist[nx][ny] = dist[t.x][t.y]+w;
                
                if(g[nx][ny]) q.push_back({nx,ny});
                else q.push_front({nx,ny});
            }
            
        }
    }
    return dist[0][0];
}
int main()
{
    int n,sx,sy;
    scanf("%d%d%d",&n,&sx,&sy);
    while(n--){
        int x,y;
        scanf("%d%d",&x,&y);
        g[x][y] = true;
    }
    printf("%d\n",bfs(sx,sy));
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

葛济维的博客

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

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

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

打赏作者

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

抵扣说明:

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

余额充值