📜  找到容纳乘客所需的火车的最小载客量(1)

📅  最后修改于: 2023-12-03 15:10:05.932000             🧑  作者: Mango

找到容纳乘客所需的火车的最小载客量

题目描述

现有$n$位乘客和若干班列车,每班列车的容量为$c_i$人,乘客可以选择搭乘任意班车,但每个班车必须按出发时间顺序依次搭乘。请问:为了让所有乘客都能搭乘班车,所需班车的最小容量是多少?

解题思路

考虑使用二分查找来解决此问题。二分查找需要找到一个合适的载客量取值范围并按照二分查找的模板来处理。进一步地,我们可以发现载客量的范围是有下限与上限的。例如,下限就是当前所有乘客中搭乘最少班车所需要的列车容量,而上限是当前所有乘客的总人数。为了得到下限,我们需要找到可能情况中最优的情况;为了得到上限,我们需要考虑所有的乘客都搭乘同一辆班车的情况,此时班车容量应等于总乘客数。

在找到合适的载客量范围的情况下,对于每一个可能的载客量取值$x$,我们都需要检查其是否满足所有的乘客可以都搭乘班车的条件。这里我们可以使用贪心算法来处理。

具体地,我们可以依次处理每一个班车,若当前班车的容量可以搭乘所有还未搭乘过班车的乘客,则这些乘客都搭乘此班车;否则,这些乘客需要分配到多个班车中。值得注意的是,我们需要遵循按出发时间依次搭乘班车的规则,因此需要记录之前已搭乘过的班车所包含的乘客信息。

复杂度分析
  • 时间复杂度:$O(n \log n \cdot \log \text{max}(a_i))$,其中$\text{max}(a_i)$表示班车容量的最大值,因为使用了二分查找和贪心算法。
  • 空间复杂度:$O(n)$,需要存储每个乘客搭乘的班车信息。
代码实现
def min_capacity(n: int, c: List[int], t: List[List[int]]) -> int:
    l, r = max(c), sum(map(len, t))
    
    while l < r:
        mid = (l + r) >> 1
        cur_t = 0
        for i, ti in enumerate(t):
            passengers = [p for p in ti if p[0] >= cur_t]
            while passengers:
                if len(passengers) > mid:
                    break
                cur_t = passengers[-1][0]
                passengers.pop()
            if passengers:
                if len(ti) - ti.index(passengers[0]) > mid:
                    break
                cur_t = passengers[0][0]
        if cur_t == t[-1][-1][0]:
            r = mid
        else:
            l = mid + 1
    
    return l
static int minCapacity(int n, int[] c, List<List<int[]>> t) {
    int l = Arrays.stream(c).max().orElseThrow();
    int r = t.stream().flatMap(List::stream).map(a -> a[1]).reduce(Integer::max).orElseThrow();
    while (l < r) {
        int mid = (l + r) >> 1;
        int curTime = 0;
        for (var ti : t) {
            var curPassengers = ti.stream()
                .filter(p -> p[0] >= curTime)
                .collect(Collectors.toCollection(ArrayList::new));
            while (!curPassengers.isEmpty() && curPassengers.size() <= mid) {
                curTime = curPassengers.remove(curPassengers.size() - 1)[1];
            }
            if (!curPassengers.isEmpty()) {
                int remainingCapacity = ti.size() - ti.indexOf(curPassengers.get(0));
                if (remainingCapacity > mid) break;
                curTime = curPassengers.get(0)[0];
            }
        }
        if (curTime == t.get(t.size() - 1).get(t.get(t.size() - 1).size() - 1)[0]) {
            r = mid;
        } else {
            l = mid + 1;
        }
    }
    return l;
}
int min_capacity(int n, vector<int> c, vector<vector<pair<int, int>>> t) {
    int l = *max_element(c.begin(), c.end());
    int r = t.back().back().second;
    while (l < r) {
        int mid = (l + r) >> 1;
        int cur_time = 0;
        for (auto& ti : t) {
            vector<pair<int, int>> cur_passengers;
            copy_if(ti.begin(), ti.end(), back_inserter(cur_passengers),
                    [&](auto& p) { return p.first >= cur_time; });
            while (!cur_passengers.empty() && cur_passengers.size() <= mid) {
                cur_time = cur_passengers.back().second;
                cur_passengers.pop_back();
            }
            if (!cur_passengers.empty()) {
                int remaining_capacity = ti.size() - (cur_passengers.front() - ti.begin());
                if (remaining_capacity > mid)
                    break;
                cur_time = cur_passengers.front().first;
            }
        }
        if (cur_time == t.back().back().first) {
            r = mid;
        } else {
            l = mid + 1;
        }
    }
    return l;
}