双端队列广搜

第一做到双端队列广搜的题目,写个博客记录一下,并且增强一下双端队列的广搜的了解

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

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

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

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

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

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

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

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

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

输入格式

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

接下来 NN 行,每行包含一个干草捆的位置坐标 (x,y)(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

题目是在一个1000*1000的矩阵里,他会告诉我们哪些地方有障碍,我们需要从给顶的起点x,y到达原点(0,0),这道题目本来是寒假的每日一题,结果那时候我连前缀和都不熟悉,所以对于双端队列广搜bfs更没有什么涉及,然后我现在回去重新做,发现了这就是一个简化版的Dijkstra,从给定起点开始,因为要求最短路,我们每次将遍历到的结点加入队列,如果该节点是存在障碍,就将dist值加一,并将该节点加入队尾,若该节点不存在障碍,则将该节点加入队首,这样第一个到达原点的值就是最小要消灭的障碍数:

注:一定要主义搜的时候不能直接将障碍值小的节点加入队列,要判断遍历到的节点的x是否在0到1001之内,y是否在0到1001之内,并且每次出队都要判重,否则会超时。

代码如下:

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
#include<deque>
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 1010;

#define x first
#define y second
bool cmp(ll a, ll b)
{
    return a < b;
}
bool cmp2(ll a, ll b)
{
    return a > b;
}

ll g[N][N];
ll dist[N][N],st[N][N];

ll bfs(ll sx,ll sy)
{
    deque<PII>q;
    q.push_front({ sx,sy });
    memset(dist, 0x3f, sizeof(dist));
    dist[sx][sy] = 0;
    int dx[4] = { 0,1,0,-1 }, dy[4] = { 1,0,-1,0 };
    while (q.size())
    {
        auto t = q.front(); q.pop_front();
        if (st[t.x][t.y])continue;
        st[t.x][t.y] = 1;
        if (t.x == 0 && t.y == 0)break;
        ll x, y;
        for (int i = 0; i <= 3; i++)
        {
            x = dx[i] + t.x, y = dy[i] + t.y;
            if (x <= 1001 && x >= 0 && y <= 1001 && y >= 0)
            {
                int w = 0;
                if (g[x][y] == 1)w = 1;
                if (dist[x][y] > dist[t.x][t.y] + w)
                {
                    dist[x][y] = dist[t.x][t.y] + w;
                    if (w == 1)q.push_back({ x,y });
                    else q.push_front({ x,y });
                }
            }
        }
    }

    return dist[0][0];
}
void work()
{
    ll n, sx,sy;
    cin >> n >> sx >> sy;
    for (int i = 1; i <= n; i++)
    {
        ll x, y;
        cin >> x >> y;
        g[x][y] = 1;
    }

    cout << bfs(sx, sy) << "\n";
}
int main()
{
    ll t = 1;
    //cin >> t;
    while (t--)
    {
        work();
    }
    return 0;
}
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值