2022.01.05 Acwing寒假每日一题 拖拉机

1、题目拖拉机

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

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

她们在田地的不同地方放了 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

2、分析

首先我们将原题进行抽象
在这里插入图片描述
橘色的是干草堆,淡蓝色的是拖拉机的位置,原点是终点。
如果我们把橘色的块权重视为1,则原题就是求一个从起点到终点的最短路。由于本图的所有权重只有0和1,所以正好可以用双端队列bfs进行处理。双端队列bfs实际上进行的是Dijkstra算法。详细的以后再补充。

3、代码

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N = 1010;
#define f first
#define s second
int w[N][N],g[N][N];
bool st[N][N];
deque<pair<int,int> > q;
int dx[4] = {0,1,0,-1};
int dy[4] = {-1,0,1,0};

int bfs(int x, int y)
{
     //先给所有w赋值无限大
    memset(w,0x3f,sizeof w);
    //起点赋值0
    w[x][y] = 0;
    q.push_back({x,y});
    
    while(q.size())
    {
        auto t = q.front();
        q.pop_front();
        
        if (st[t.f][t.s]) continue;
        st[t.f][t.s] = true;
        
        if(!t.f && !t.s) return w[0][0];
        
        for(int i = 0; i < 4; i ++)
        {
            int nx = t.f + dx[i];
            int ny = t.s + dy[i];
            
            if(ny >= 0 && ny <= 1001 && nx >= 0 && ny <= 1001) 
            {
                if(w[nx][ny] > w[t.f][t.s] + g[nx][ny])
                {
                    w[nx][ny] = w[t.f][t.s] + g[nx][ny];
                    if(!g[nx][ny]) q.push_front({nx,ny});
                    else q.push_back({nx,ny});
                }
            }
        }
    }
}
int main()
{
    int n,x,y;
    cin >> n >> x >> y;
    for(int i = 0; i < n; i ++)
    {
        int a,b;
        cin >> a >> b;
        g[a][b] ++;
    }
    cout << bfs(x,y);
}

4、总结

  1. 边权值只有01的最短路问题可以使用双端队列进行处理

参考资料

Acwing

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值