UVa 1450 Airport

问题描述

一个大城市有一个年客流量 400040004000 万的国际机场,但该机场以世界上最为拥堵的机场之一而臭名昭著。在这个机场,只有一条跑道。因此,跑道上总是挤满了等待起飞的飞机。有两条路可以接近跑道,分别称为西路 WWW 和东路 EEE 。飞机在这两条路上等待起飞。

在每个时刻 ttt ,任意数量的飞机到达西路 WWW 和东路 EEE 。每个在时刻 ttt 到达 WWWEEE 的飞机会获得一个等级,该等级等于同一条路上排在它前面的等待飞机的数量。然后,控制塔会选择 WWWEEE 之一,让该路上最前面的飞机起飞。给定飞机到达时刻的信息,我们关注控制塔的起飞调度方案,以使所有飞机的最大等级最小化。

输入格式

输入包含 TTT 个测试用例。测试用例的数量 TTT 在输入的第一行给出。每个测试用例的第一行包含一个整数 nnn (1≤n≤5000)(1 \leq n \leq 5000)(1n5000) ,表示时刻的数量。在每个测试用例接下来的 nnn 行中,第 iii 行包含两个整数 aia_iaibib_ibi ,分别表示时刻 iii 到达西路 WWW 和东路 EEE 的飞机数量,其中 0≤ai,bi≤200 \leq a_i, b_i \leq 200ai,bi20

输出格式

为每个测试用例输出一行,包含所有可能起飞调度方案中最大等级的最小值。

题目分析

这是一个经典的调度优化问题,我们需要在满足每时刻只能起飞一架飞机的约束下,最小化所有飞机在所有时刻出现的最大等待等级。

问题转化

首先理解等级的计算方式:一架飞机在时刻 ttt 到达时,它的等级等于同一条路上排在它前面的飞机数量。注意这个等级是在到达时刻计算的,之后如果前面的飞机起飞了,这架飞机的等级会减小,但我们关心的是 所有飞机在所有时刻曾经达到过的最大等级

设:

  • totalW[i]totalW[i]totalW[i] 表示到时刻 iii 为止,西路 WWW 累计到达的飞机总数
  • totalE[i]totalE[i]totalE[i] 表示到时刻 iii 为止,东路 EEE 累计到达的飞机总数
  • takeW[i]takeW[i]takeW[i] 表示到时刻 iii 为止,从西路 WWW 起飞的飞机总数
  • takeE[i]takeE[i]takeE[i] 表示到时刻 iii 为止,从东路 EEE 起飞的飞机总数

由于每时刻只能起飞一架飞机,我们有:
takeW[i]+takeE[i]=i takeW[i] + takeE[i] = i takeW[i]+takeE[i]=i

在时刻 iii ,西路 WWW 上等待的飞机数为:
waitW[i]=totalW[i]−takeW[i] waitW[i] = totalW[i] - takeW[i] waitW[i]=totalW[i]takeW[i]

东路 EEE 上等待的飞机数为:
waitE[i]=totalE[i]−takeE[i] waitE[i] = totalE[i] - takeE[i] waitE[i]=totalE[i]takeE[i]

在时刻 iii 新到达的飞机中,最后到达的那架飞机(即等级最高的)的等级为:

  • 西路:waitW[i−1]+a[i]−1waitW[i-1] + a[i] - 1waitW[i1]+a[i]1
  • 东路:waitE[i−1]+b[i]−1waitE[i-1] + b[i] - 1waitE[i1]+b[i]1

这里 waitW[i−1]waitW[i-1]waitW[i1] 表示时刻 iii 之前已经在等待的飞机数,a[i]−1a[i]-1a[i]1 表示在同一时刻到达但排在前面的飞机数。

我们的目标是找到一种调度方案,使得:
max⁡i(max⁡(waitW[i−1]+a[i]−1, waitE[i−1]+b[i]−1)) \max_{i} \left( \max(waitW[i-1] + a[i] - 1, \ waitE[i-1] + b[i] - 1) \right) imax(max(waitW[i1]+a[i]1, waitE[i1]+b[i]1))

最小化。

关键观察

注意到 waitW[i]=totalW[i]−takeW[i]waitW[i] = totalW[i] - takeW[i]waitW[i]=totalW[i]takeW[i]takeW[i]+takeE[i]=itakeW[i] + takeE[i] = itakeW[i]+takeE[i]=i ,所以 waitE[i]=totalE[i]−(i−takeW[i])waitE[i] = totalE[i] - (i - takeW[i])waitE[i]=totalE[i](itakeW[i])

设最大等待飞机数的上限为 midmidmid (注意:最大等级 = 最大等待数 - 111),那么我们需要保证在任意时刻 iii

  1. waitW[i]=totalW[i]−takeW[i]≤midwaitW[i] = totalW[i] - takeW[i] \leq midwaitW[i]=totalW[i]takeW[i]mid
  2. waitE[i]=totalE[i]−(i−takeW[i])≤midwaitE[i] = totalE[i] - (i - takeW[i]) \leq midwaitE[i]=totalE[i](itakeW[i])mid

这两个不等式可以转化为对 takeW[i]takeW[i]takeW[i] 的约束:

  1. takeW[i]≥totalW[i]−midtakeW[i] \geq totalW[i] - midtakeW[i]totalW[i]mid
  2. takeW[i]≤totalE[i]−mid+itakeW[i] \leq totalE[i] - mid + itakeW[i]totalE[i]mid+i

此外,还有基本约束:

  • takeW[i]≥0takeW[i] \geq 0takeW[i]0
  • takeW[i]≤totalW[i]takeW[i] \leq totalW[i]takeW[i]totalW[i] (不能起飞超过已到达的飞机数)
  • takeW[i]≤itakeW[i] \leq itakeW[i]i (起飞总数不能超过时刻数)
  • i−takeW[i]≤totalE[i]i - takeW[i] \leq totalE[i]itakeW[i]totalE[i] (东路起飞数不能超过东路到达数)

解题思路

二分答案

由于答案具有单调性(如果最大等级 kkk 可行,那么 k+1k+1k+1 也一定可行),我们可以使用二分查找来寻找最小的可行最大等级。

对于给定的 midmidmid ,我们需要判断是否存在一个调度方案,使得所有时刻的等待飞机数都不超过 midmidmid

贪心验证

验证函数 check(mid) 的核心思想是维护 takeWtakeWtakeW 的可能取值范围 [L,R][L, R][L,R] ,然后逐时刻更新这个范围。

初始化:L=0, R=0L = 0, \ R = 0L=0, R=0 (第 000 时刻未起飞任何飞机)

对于每个时刻 iii

  1. 更新累计到达飞机数:totalW+=a[i], totalE+=b[i]totalW += a[i], \ totalE += b[i]totalW+=a[i], totalE+=b[i]
  2. 由于必须起飞一架飞机,takeWtakeWtakeW 最多可以增加 111R=R+1R = R + 1R=R+1
  3. 应用基本约束:R=min⁡(R, totalW)R = \min(R, \ totalW)R=min(R, totalW) (不能起飞超过已到达的飞机数)
  4. 应用等待数约束:
    • 从不等式 takeW≥totalW−midtakeW \geq totalW - midtakeWtotalWmid 得:L=max⁡(L, totalW−mid)L = \max(L, \ totalW - mid)L=max(L, totalWmid)
    • 从不等式 takeW≤totalE−mid+itakeW \leq totalE - mid + itakeWtotalEmid+i 得:R=min⁡(R, totalE−mid+i)R = \min(R, \ totalE - mid + i)R=min(R, totalEmid+i)
  5. 应用其他边界约束:
    • L=max⁡(L, 0)L = \max(L, \ 0)L=max(L, 0)
    • L=max⁡(L, i−totalE)L = \max(L, \ i - totalE)L=max(L, itotalE) (确保 takeE=i−takeW≤totalEtakeE = i - takeW \leq totalEtakeE=itakeWtotalE
    • R=min⁡(R, i)R = \min(R, \ i)R=min(R, i)
    • R=min⁡(R, totalW)R = \min(R, \ totalW)R=min(R, totalW)
  6. 如果 L>RL > RL>R ,则当前 midmidmid 不可行

如果处理完所有时刻后 L≤RL \leq RLR ,则 midmidmid 可行。

算法复杂度

  • 二分查找:O(log⁡M)O(\log M)O(logM) ,其中 MMM 是飞机总数的上界,最大为 5000×20×2=2000005000 \times 20 \times 2 = 2000005000×20×2=200000
  • 每次验证:O(n)O(n)O(n)n≤5000n \leq 5000n5000
  • 总复杂度:O(T×n×log⁡M)O(T \times n \times \log M)O(T×n×logM) ,在题目限制下完全可行

代码实现

// Airport
// UVa ID: 1450
// Verdict: Accepted
// Submission Date: 2025-12-16
// UVa Run Time: 0.010s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net

#include <bits/stdc++.h>
using namespace std;

const int N = 5005;

int t, n, a[N], b[N];

// 检查最大等待数不超过 mid 是否可行
bool check(int mid) {
    int an = 0, bn = 0, have = 0;  // an: W路累计等待数, bn: E路累计等待数, have: 可用起飞时隙
    for (int i = 0; i < n; i++) {
        an += a[i];  // 更新W路累计等待数
        bn += b[i];  // 更新E路累计等待数
        
        // 计算至少需要从各条路起飞的飞机数
        int needa = max(an - mid, 0);
        int needb = max(bn - mid, 0);
        
        // 如果需要的起飞数超过可用时隙,则不可行
        if (needa + needb > have) return false;
        
        // 更新可用起飞时隙和等待数
        if (an == 0 && bn > 0) bn--;           // 只能从E路起飞
        else if (bn == 0 && an > 0) an--;      // 只能从W路起飞
        else if (an > 0 && bn > 0 && an + bn > have) have++;  // 两条路都有飞机,增加起飞机会
    }
    return true;
}

// 二分查找最小可行最大等待数
int solve() {
    int left = 0, right = 100000;  // 等待数上界
    while (left < right) {
        int mid = (left + right) / 2;
        if (check(mid)) right = mid;
        else left = mid + 1;
    }
    // 最大等级 = 最大等待数 - 1
    return left == 0 ? 0 : left - 1;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    cin >> t;
    while (t--) {
        cin >> n;
        for (int i = 0; i < n; i++) cin >> a[i] >> b[i];
        cout << solve() << "\n";
    }
    
    return 0;
}

代码解析

  1. 输入处理 :使用 cin 读取输入,关闭同步以提高效率。
  2. 验证函数 check(mid) :实现上述贪心验证逻辑。
    • anbn 分别记录两条路的累计等待飞机数
    • have 记录可用的起飞时隙数(即已过去的时间)
    • needaneedb 分别表示为了保持等待数不超过 midmidmid ,至少需要从各条路起飞的飞机数
  3. 二分查找 :在范围 [0,100000][0, 100000][0,100000] 内查找最小可行最大等待数。
  4. 输出处理 :注意最大等级 = 最大等待数 - 1 ,所以最终答案为 left - 1

样例分析

样例输入

3
1
1 1
3
3 2
0 3
2 0
6
0 1
1 1
1 2
1 1
1 1
6 0

样例输出

0
3
5

解释

  1. 第一个测试用例:只有 111 个时刻,两条路各到达 111 架飞机。最优调度是立即从任意一条路起飞一架飞机,最大等级为 000
  2. 第二个测试用例:需要仔细调度才能得到最大等级 333 ,如题目中的示例所示。
  3. 第三个测试用例:通过合理调度,可以使得最大等级为 555

总结

本题的关键在于将问题转化为对最大等待飞机数的约束,然后使用二分答案和贪心验证的方法求解。贪心验证的核心是维护 takeWtakeWtakeW 的可能取值范围,通过逐时刻更新约束条件来判断可行性。这种解法既高效又易于实现,能够处理题目中的最大数据规模。

算法的时间复杂度为 O(T×n×log⁡M)O(T \times n \times \log M)O(T×n×logM) ,空间复杂度为 O(n)O(n)O(n) ,完全满足题目要求。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值