旅行问题(单调队列)

博客探讨了一个环形公路上的旅行问题,John需要从某个车站出发,按顺时针或逆时针方向行驶并返回起点。问题转化为判断每个车站是否能成功完成旅行,利用单调队列解决这个问题。博客详细解释了思路,包括如何破环成链,以及顺时针和逆时针方向的处理方式,最后给出了单调队列解法的时间复杂度。
摘要由CSDN通过智能技术生成

旅行问题

John 打算驾驶一辆汽车周游一个环形公路。

公路上总共有 n 个车站,每站都有若干升汽油(有的站可能油量为零),每升油可以让汽车行驶一千米。

John 必须从某个车站出发,一直按顺时针(或逆时针)方向走遍所有的车站,并回到起点。

在一开始的时候,汽车内油量为零,John 每到一个车站就把该站所有的油都带上(起点站亦是如此),行驶过程中不能出现没有油的情况。

任务:判断以每个车站为起点能否按条件成功周游一周。

输入格式
第一行是一个整数 n,表示环形公路上的车站数;

接下来 n 行,每行两个整数 pi,di,分别表示表示第 i 号车站的存油量和第 i 号车站到 顺时针方向 下一站的距离。

输出格式
输出共 n 行,如果从第 i 号车站出发,一直按顺时针(或逆时针)方向行驶,能够成功周游一圈,则在第 i 行输出 TAK,否则输出 NIE。

数据范围
3≤n≤106,
0≤pi≤2×109,
0≤di≤2×109
输入样例:
5
3 1
1 2
5 2
0 1
5 4
输出样例:
TAK
NIE
TAK
NIE
TAK
思路分析:这是一道经典的单调队列问题,我们首先考虑顺时针方向,我们需要破环成链,破环成链的方法为使长度为2倍,123456789123456789这样的序列即可破环成链在这里插入图片描述
考虑对于第i个点,固定第i个点之后先后出发经过n个点,这里需要满足的条件为区间长度为n的这段区间中前缀和的最小值与sum[i]的大小比较,如果比这个值大,说明可以环游一周,否则不能从这个点顺时针环游一周,而每个值为每个点的加油量p[i]-距离d[i],遍历时应该从2*n开始遍历,总结后就是下面几点
每个点i表示从i点加pl[i]的油再耗d[i]的油所剩的油量,即p[i] - d[i]

1、计算出油量的前缀和
2、从某个点i出发,顺时针走一圈,在过程中油量始终 >= 0,等价于在[i,i + n - 1]中,对任意的j,i <= j <= i + n - 1,均有sum[j] - sum[i - 1] >= 0,即i固定,找sum[j]的最小值,即从[i,i + n - 1]中找到滑动窗口的最小值
3、由于2操作,需要对i进行反向遍历,即从n * 2遍历到1,又由于i <= j <= i + n - 1,遍历到i时需要用到i位置的值,因此找[i,i + n - 1]区间最小值时需要在while后面的语句找
逆时针方向
在这里插入图片描述每个点i表示从i点加p[i]的油再耗d[i - 1]的油所剩的油量,即p[i] - d[i - 1],其中1号点浩的是d[n]的油,因此需要初始化d[0] = d[n]

1、计算出油量的后缀和
2、从某个点i出发,逆时针走一圈,在过程中油量始终 >= 0,等价于在[i - n + 1,i]中,对任意的j,i - n + 1 <= j <= i,均有sum[j] - sum[i + 1] >= 0,即i固定,找sum[j]的最小值,即从[i - n + 1,i]中找到滑动窗口的最小值
3、由于2操作,需要对i进行正向遍历,即从1遍历到n * 2,又由于i - n + 1 <= j <= i,遍历到i时需要用到i位置的值,因此找[i - n + 1,i]区间最小值时需要在while后面的语句找

单调队列的时间复杂度为O(n)

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e6+10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值