一个有意思的代码问题--万圣节

题目描述

一年一度的万圣节马上就要到了,弓箭手小明和剑士小刚约好一起去猎杀幽灵,一共有n个幽灵,第i只幽灵会掉落ai件弓箭手装备,bi个剑士装备。 
小明的收获总和是他猎杀的幽灵的ai值之和。小刚的收获总和是他猎杀的幽灵的bi值之和。小明小刚轮流行动,小明先手。两人都能保证一击必杀。 
小明和小刚的目的尽可能让自己收获比对方高。你需要求出两人都使用最优策略的情况下,输出他们的收获差。我们保证所有幽灵掉落装备总价值不同。 

输入

第一行输入一个正整数n表示幽灵个数  
第二行输入n个数a1,a2,a3.....an  
第三行输入n个数b1,b2,b3.....bn。 
题目保证1≤n≤105, -109≤ai,bi≤109。 

输出

两人都使用最优策略的情况下,他们的收获的差值(取绝对值)

样例输入 Copy
3
8 7 6
5 4 2
样例输出 Copy
10

这个题目很有意思,开始我是想答案是小明和小刚各自都选择价值最大的,获得答案。可结果并非如此,我们应该选择对自己最优的,而最优的是选择a+b最大的。

为什么按 a_i + b_i 排序才是最优?

核心思想

  • 每次选 a_i + b_i 最大的幽灵,能保证:

    • 当前玩家能拿到 对自己最有利的幽灵(因为 a_i + b_i 大意味着要么 a_i 很大,要么 b_i 很大)。

    • 同时 减少对方后续能拿的高收益幽灵(因为 a_i + b_i 大的幽灵被优先移除)。

重新计算前面的例子

输入

复制

下载

a = [10, 5, 3]  
b = [1, 8, 2]
  • 计算 a_i + b_i

    • (10,1) → 11

    • (5,8) → 13

    • (3,2) → 5

  • 按 a_i + b_i 降序排序[(5,8), (10,1), (3,2)]

  • 轮流选择

    1. 小明选 (5,8)(因为 5+8=13 最大),拿 a_i=5sum_a = 5
      移除后:a=[10,3]b=[1,2]

    2. 小刚选 (10,1)(因为 10+1=11 最大),拿 b_i=1sum_b = 1
      移除后:a=[3]b=[2]

    3. 小明选 (3,2),拿 a_i=3sum_a = 5 + 3 = 8

  • 最终差值|8 - 1| = 7(比之前的 5 更优!)


3. 为什么这样更优?

  • 小明先手,如果直接选 a_i 最大的 10,小刚后续可以选 b_i 最大的 8,导致小刚收益较高。

  • 但按 a_i + b_i 排序,小明会优先选 (5,8)(虽然 a_i=5 不是最大,但 b_i=8 很大,选它能阻止小刚拿 8)。

    • 这样小刚只能拿 (10,1),收益很低(b_i=1)。

    • 最终小明的收益 8 比小刚的 1 多 7,这才是 真正的最优策略

      """
      幽灵问题:
      最优策略是:选择a+b中最大的
      如果双方都只图眼前利益,拿自己眼中看到的最大值不一定获得最优解
      选择a+b意味着:你拿到的要么是自己最大的,要么是对方最大的
      """
      n=int(input())
      arr=list(map(int,input().split()))
      brr=list(map(int,input().split()))
      # zip将arr,brr列表合并为元组,相加降序排列
      r=sorted(zip(arr,brr),key=lambda x:-(x[0]+x[1]))
      a,b=0,0
      for i in range(len(r)):
          if i%2==0:
              a+=r[i][0]
          else:
              b+=r[i][1]
      print(abs(a-b))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值