UVa 10640 Planes around the World
题目描述
我们有若干架飞机位于地点 AAA ,每架飞机满油可以飞行地球圆周的 a/ba/ba/b 。例如,当 a=1a=1a=1 , b=2b=2b=2 时,每架飞机可以飞行半个地球(从 AAA 到 BBB )。借助高科技,飞机可以瞬间交换燃油(但任何时候飞机携带的燃油不能超过油箱容量)。我们可以使用多架飞机来确保其中一架能够完成环球飞行,并且所有飞机最终都能返回 AAA 。题目要求找出完成这一任务所需的最少飞机数量。
输入格式
第一行包含一个整数 ttt ( 1≤t≤501 \leq t \leq 501≤t≤50 ),表示测试用例的数量。每个测试用例包含两个整数 aaa 和 bbb ( 0≤a,b≤1500 \leq a, b \leq 1500≤a,b≤150 , b≠0b \neq 0b=0 )。
输出格式
对于每个测试用例,输出格式为 Case X: Y,其中 YYY 是最少所需飞机数。如果 100001000010000 架飞机都不够,则输出 −1-1−1 。
题目分析
这是一个经典的燃油接力问题,类似于“沙漠穿越”问题,但增加了环球飞行和对称性的考虑。我们需要让一架飞机(称为环球飞机)飞行整个地球圆周(距离设为 111 ),其他飞机辅助加油并最终全部返回起点。
关键观察
-
对称性:由于环球飞行是闭合的,前半程( 000 到 0.50.50.5 )和后半程( 0.50.50.5 到 111 )是对称的。因此,我们可以将辅助飞机分为两组:一组用于前半程,一组用于后半程。
-
燃油共享:飞机可以瞬间交换燃油,这意味着当多架飞机一起飞行时,它们的燃油可以视为一个共享的油池。
-
折返条件:当一架辅助飞机折返时,它会将剩余燃油均匀分给其他仍在飞行的飞机,确保自己能够返回起点。
数学模型
设:
- 地球周长 = 111 (单位化)
- 每架飞机满油可飞行距离 r=a/br = a/br=a/b
- 前半程使用 iii 架辅助飞机
- 后半程使用若干架辅助飞机
前半程分析:
当有 iii 架辅助飞机时,环球飞机在前半程结束时能飞行的距离为:
s=2ii+1⋅r s = \frac{2i}{i+1} \cdot r s=i+12i⋅r
这个公式的推导基于最优接力策略:当有 kkk 架飞机一起飞行时,它们可以支持环球飞机前进 r/(k+1)r/(k+1)r/(k+1) 的距离,通过累加得到上述结果。
要使环球飞机能够完成飞行,前半程结束时必须满足:
s>1−r s > 1 - r s>1−r
否则,即使环球飞机在后半程开始时满油,也无法飞完后半程。
后半程分析:
设环球飞机已经飞行了距离 sss ,还需要飞行 1−s1-s1−s 的距离。我们逐架添加辅助飞机:
- 当添加第 jjj 架辅助飞机时,它需要飞行 1−s1-s1−s 的距离与环球飞机会合
- 会合后,它剩余的燃油为 r−(1−s)r - (1-s)r−(1−s)
- 这些燃油被平均分给所有 j+1j+1j+1 架飞机(包括环球飞机和已添加的辅助飞机)
- 因此,环球飞机能飞行的距离增加量为:
r−(1−s)j+1 \frac{r - (1-s)}{j+1} j+1r−(1−s)
我们不断添加辅助飞机,直到环球飞机累计飞行距离 s≥1s \geq 1s≥1 。
算法步骤
- 特判:
- 如果 a=0a=0a=0 ,输出 −1-1−1
- 如果 a≥ba \geq ba≥b ,一架飞机即可环球,输出 111
- 枚举前半程辅助飞机数 iii ,从 111 开始:
- 计算前半程结束距离 s=2ii+1⋅rs = \frac{2i}{i+1} \cdot rs=i+12i⋅r
- 如果 s≤1−rs \leq 1-rs≤1−r ,说明前半程飞不完,跳过
- 否则,计算后半程所需辅助飞机数:
- 初始化 cnt=1cnt = 1cnt=1 (环球飞机)
- 当 s<1s < 1s<1 时,不断添加辅助飞机,更新 sss 和 cntcntcnt
- 总飞机数为 i+cnt−1i + cnt - 1i+cnt−1
- 取所有枚举中的最小值作为答案
- 如果答案大于 100001000010000 ,输出 −1-1−1 ,否则输出答案
时间复杂度
外层循环最多枚举 100001000010000 次,内层循环最多添加 100001000010000 架飞机,但实际运行中会提前剪枝。对于 t≤50t \leq 50t≤50 的测试数据,可以在时限内通过。
代码实现
// Planes around the World
// UVa ID: 10640
// Verdict: Accepted
// Submission Date: 2026-01-21
// UVa Run Time: 0.000s
//
// 版权所有(C)2026,邱秋。metaphysis # yeah dot net
#include <bits/stdc++.h>
using namespace std;
int main() {
int t;
scanf("%d", &t);
for (int caseNo = 1; caseNo <= t; caseNo++) {
int a, b;
scanf("%d %d", &a, &b);
if (a == 0) {
printf("Case %d: -1\n", caseNo);
continue;
}
if (a >= b) {
printf("Case %d: 1\n", caseNo);
continue;
}
double r = (double)a / b;
int needed = 10001;
// 枚举前半程辅助飞机数i
for (int i = 1; i < needed; i++) {
// 计算前半程结束时环球飞机能飞的距离
double s = (2.0 * i * a) / ((i + 1.0) * b);
// 如果前半程飞不完,继续尝试更大的i
if (s <= 1.0 - r + 1e-9) continue;
int cnt = 1; // 已经使用的飞机数(环球飞机)
while (s < 1.0 - 1e-9) {
// 如果已经超过当前最优解,提前结束
if (i + cnt - 1 >= needed) break;
// 添加一架辅助飞机
s += (r - (1.0 - s)) / (cnt + 1.0);
cnt++;
}
// 更新答案:前半程i架辅助飞机,后半程(cnt-1)架辅助飞机
if (s >= 1.0 - 1e-9) needed = min(needed, i + cnt - 1);
}
if (needed > 10000) printf("Case %d: -1\n", caseNo);
else printf("Case %d: %d\n", caseNo, needed);
}
return 0;
}
示例验证
样例输入
3
1 2
1 3
2 5
样例输出
Case 1: 5
Case 2: -1
Case 3: 13
对于第一个测试用例( a=1a=1a=1 , b=2b=2b=2 ):
- r=0.5r=0.5r=0.5
- 当 i=3i=3i=3 时, s=0.75>0.5s=0.75 > 0.5s=0.75>0.5
- 后半程需要添加 222 架辅助飞机( cntcntcnt 从 111 增加到 333 )
- 总飞机数 =3+3−1=5= 3 + 3 - 1 = 5=3+3−1=5
对于第二个测试用例( a=1a=1a=1 , b=3b=3b=3 ):
- r≈0.333r \approx 0.333r≈0.333
- 需要很大的 iii 才能满足 s>1−r≈0.667s > 1-r \approx 0.667s>1−r≈0.667
- 计算出的飞机数超过 100001000010000 ,输出 −1-1−1
对于第三个测试用例( a=2a=2a=2 , b=5b=5b=5 ):
- r=0.4r=0.4r=0.4
- 当 i=6i=6i=6 时, s=0.75>0.6s=0.75 > 0.6s=0.75>0.6
- 后半程需要添加 666 架辅助飞机
- 总飞机数 =6+6−1=13= 6 + 6 - 1 = 13=6+6−1=13
总结
本题的关键在于理解燃油接力的数学模型,特别是对称性带来的简化。通过枚举前半程辅助飞机数,并动态计算后半程所需飞机数,我们可以高效地找到最少飞机数量。算法的时间复杂度在实际数据范围内是可接受的,且能够正确处理边界情况。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)