加油站良好出发点问题

加油站良好出发点问题

题目描述

N个加油站组成一个环形,给定两个长度都是N的非负数组oil和dis(N>1),oil[i]代表第i个加油站存的油可以跑多少千米,dis[i]代表第i个加油站到环中下一个加油站相隔多少千米。假设你有一辆油箱足够大的车,初始时车里没有油。如果车从第i个加油站出发,最终可以回到这个加油站,那么第i个加油站就算良好出发点,否则就不算。请返回长度为N的boolean型数组res,res[i]代表第i个加油站是不是良好出发点

规定只能按照顺时针走,也就是i只能走到i+1,N只能走到1

[要求]

时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( 1 ) O(1) O(1)

输入描述:

第一行一个整数N表示加油站数量。
第二行N个整数,表示oil数组。
第三行N个整数,表示dis数组。

输出描述:

输出N个整数。若第i个整数为0表示该位置不是良好出发点,为1表示该位置是良好出发点。

示例1
输入
9
4 2 0 4 5 2 3 6 2
6 1 3 1 6 4 1 1 6
输出
0 0 0 0 0 0 0 0 0
示例2
输入
8
4 5 3 1 5 1 1 9
1 9 1 2 6 0 2 0
输出
0 0 1 0 0 1 0 1
说明
如果车从A点出发,到B点且加上B的油,还剩8的油,发现到不了C;
如果从B点出发,发现车到不了C;
如果从C点出发,发现可以转一圈,所以C点是良好出发点。
……
备注:

1 ⩽ N ⩽ 1 0 5 1 \leqslant N \leqslant 10^5 1N105
0 ⩽ o i l [ i ] , d i s [ i ] ⩽ 1 0 9 0 \leqslant oil[i], dis[i] \leqslant 10^9 0oil[i],dis[i]109


题解:

贪心的思想。我们设置一个区间 [start, end) ,表示车可以从 start 开始,达到 end 的前一个位置。其中 start 我们任意挑选一个 o i l [ i ] > = d i s [ i ] oil[i] >= dis[i] oil[i]>=dis[i] 的位置开始,而 e n d = ( s t a r t + 1 ) end = (start + 1) % n end=(start+1),若车能到达,表明可以走完一圈。我们可以提前利用: o i l [ i ] − d i s [ i ] oil[i]-dis[i] oil[i]dis[i]记录每个车站剩下的油量。

从 start 开始遍历,使用一个变量 rest 记录剩余的油量,初始值为 o i l [ s t a r t ] − d i s [ s t a r t ] oil[start] - dis[start] oil[start]dis[start]

  • 若 rest >= 0,尝试扩展 end ,即: r e t + = o i l [ e n d ] ; e n d = ( e n d + 1 ) ret += oil[end]; end = (end + 1) % n; ret+=oil[end];end=(end+1)
  • 若 rest < 0,向 start 左边扩展,尝试查看上一个车站能否补充现在的差额,即: s t a r t = ( s t a r t − 1 + n ) start = (start - 1 + n) % n; rest += oil[start]; start=(start1+n)
  • 当 start == end 时停止;

若最终 rest >= 0​ ,说明 start 是一个良好出发点。对于剩下的点,我们从 start 开始往左边移动:

  • 若 rest >=0 ,说明当前位置是一个良好出发点,往左移动,继续判断上一个点,即:start = (start - 1 + n) % n; rest = oil[start];
  • 否则,当前位置不是一个良好出发点,往左寻找可能补充差额的站,即:start = (start - 1 + n) % n; rest += oil[start];
代码:
#include <cstdio>

using namespace std;

typedef long long LL;

const int N = 100000;

int oil[N];
int dis[N];
bool ret[N];

int main(void) {
    int n;
    scanf("%d", &n);
    for ( int i = 0; i < n; ++i )
        scanf("%d", oil + i );
    int st = -1, ed;
    for ( int i = 0; i < n; ++i ) {
        scanf("%d", dis + i);
        oil[i] -= dis[i];
        
        if ( oil[i] >= 0 ) st = i;
    }
    if ( st == -1 ) {
        for ( int i = 0; i < n; ++i )
            printf("%d%c", ret[i], " \n"[i == n - 1]);
        return 0;
    }
    ed = (st + 1) % n;
    LL rest = oil[st];
    while ( st != ed ) {
        if ( rest >= 0 ) {
            rest += oil[ed];
            ed = (ed + 1) % n;
        } else {
            st = (st - 1 + n) % n;
            rest += oil[st];
        }
    }
    if ( rest >= 0 ) {
        for ( int i = 0; i < n; ++i ) {
            if ( rest >= 0 ) {
                ret[st] = 1;
                st = (st - 1 + n) % n;
                rest = oil[st];
            } else {
                ret[st] = 0;
                st = (st - 1 + n) % n;
                rest += oil[st];
            }
        }
    }
    for ( int i = 0; i < n; ++i )
            printf("%d%c", ret[i], " \n"[i == n - 1]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值