目录
题目描述
题源:洛谷
解题
思路:贪心算法+双指针
-
将双方马匹都排序
-
用我们最快的马尽可能赢对方最快的马
-
当无法赢时,用最差的马消耗对方最好的马
情况一:我们最快的马可以赢田忌最快的马
也就是我们的列表最大值(最后一个)的值大于田忌列表中最后一个:
our_horses[our_right] > tianji_horses[tianji_right]
那么,赢得场次+1,快指针往前移动:
win += 1
our_right -= 1
tianji_right -= 1
情况二:我们最快的马不能赢田忌最快的马
子情况2.1:我们最慢的马能赢田忌最慢的马
our_horses[our_right] > tianji_horses[tianji_right]
能赢,则赢得场次会+1,同时左指针均会右移
win += 1
our_left += 1
tianji_left += 1
解释这个为什么:
我们的最慢的马能稳赢对方最慢的马,这样能确保 至少拿到 1 胜
如果我们不这样做,可能会被迫用快马去赢慢马
-
情况2.1 是在 无法用最快马赢对方最快马 时,检查 是否能用最慢马赢对方最慢马。
-
如果能,就 直接拿下这 1 胜,避免后续更糟的对局。
-
这是 贪心策略的一部分,确保每一步都尽量获取最大收益。
情况2.1 和 情况2.2 共同作用,才能得到全局最优解! 🚀
子情况2.2:我们最慢的马不能赢田忌最慢的马
用我们最慢的马去消耗田忌最快的马(故意输掉这轮),让田忌最快的马被"兑子"掉,保留我们的好马去赢田忌的中等马
our_horses[our_right] <= tianji_horses[tianji_right]
#注意相等也是没有赢
我们的左指针右移,田忌的右指针左移
our_left += 1
tianji_right -= 1
解释这个为什么是最优:
此时说明,我们的最慢的马已经无法赢任何马, our_horses[our_left] ≤ tianji_horses[tianji_left]
,说明我们的最慢的马比田忌最慢的马还慢,无法赢任何马。
与其让它去输给田忌最慢的马,不如让它去输给田忌最快的马,这样还能让田忌最快的马被消耗掉。相当于用最差的马换掉对方最强的马,保留我们的中等马去赢田忌的中等马。
举例说明
假设:
-
我们的马(已排序):
[1, 3, 5]
-
田忌的马(已排序):
[2, 4, 6]
写了情况2.2会:😊
5<6 (不能赢)1<2 (不能赢)
此时会拿我们的1和田忌的6比较,用1消耗掉6,最终3就可以PK掉田忌的2
现在剩余马匹:我们:[3, 5]
田忌:[2, 4]
最终 5>4 3>2 胜2场✅
没有2.2的话:
5<6 (不能赢)
不执行2.2,而是直接跳过,尝试其他匹配方式,让 5
去对 4
→ 5 > 4
(赢),消耗 5
和 4
现在剩余马匹:我们的 [1, 3]
田忌的 [2, 6]
让 3
对 6
→ 3 ≤ 6
(不能赢)
让 1
对 2
→ 1 ≤ 2
(不能赢)
最终胜1场
完整代码
# 读取输入的马匹数量
n = int(input())
# 读取我们的马匹速度列表并排序(升序)
our_horses = list(map(int, input().split()))
our_horses.sort()
# 读取田忌的马匹速度列表并排序(升序)
tianji_horses = list(map(int, input().split()))
tianji_horses.sort()
# 初始化获胜场次计数器
win = 0
# 初始化双指针:
# our_left/tianji_left 指向当前最慢的马(列表最左端)
# our_right/tianji_right 指向当前最快的马(列表最右端)
our_left = tianji_left = 0
our_right = tianji_right = n - 1
# 主循环:当还有未比赛的马时继续
while our_left <= our_right:
# 情况1:我们最快的马能赢田忌最快的马
if our_horses[our_right] > tianji_horses[tianji_right]:
win += 1 # 赢得一场
our_right -= 1 # 我们这匹马已用
tianji_right -= 1 # 田忌这匹马已用
# 情况2:我们最快的马不能赢田忌最快的马
else:
# 子情况2.1:我们最慢的马能赢田忌最慢的马
if our_horses[our_left] > tianji_horses[tianji_left]:
win += 1 # 赢得一场
our_left += 1 # 我们这匹马已用
tianji_left += 1 # 田忌这匹马已用
# 子情况2.2:我们最慢的马也不能赢田忌最慢的马
else:
# 用我们最慢的马消耗田忌最快的马(必输策略)
our_left += 1 # 我们这匹马已用
tianji_right -= 1 # 田忌这匹马已用
# 输出最终能获胜的场次
print(win)
运行结果
AC