您现在的位置是:首页 > 技术教程 正文

蓝桥杯笔记-2023年第十四届省赛真题-三国游戏(Python)

admin 阅读: 2024-03-21
后台-插件-广告管理-内容页头部广告(手机)

题目描述

小蓝正在玩一款游戏。游戏中魏蜀吴三个国家各自拥有一定数量的士兵X, Y, Z (一开始可以认为都为 0 )。游戏有 n 个可能会发生的事件,每个事件之间相互独立且最多只会发生一次,当第 i 个事件发生时会分别让 X, Y, Z 增加Ai , Bi ,Ci 。

当游戏结束时 (所有事件的发生与否已经确定),如果 X, Y, Z 的其中一个大于另外两个之和,我们认为其获胜。例如,当 X > Y + Z 时,我们认为魏国获胜。小蓝想知道游戏结束时如果有其中一个国家获胜,最多发生了多少个事件?

如果不存在任何能让某国获胜的情况,请输出 −1 。

输入格式

输入的第一行包含一个整数 n 。

第二行包含 n 个整数表示 Ai,相邻整数之间使用一个空格分隔。

第三行包含 n 个整数表示 Bi,相邻整数之间使用一个空格分隔。

第四行包含 n 个整数表示 Ci,相邻整数之间使用一个空格分隔。

输出格式

输出一行包含一个整数表示答案。

样例输入

3 1 2 2 2 3 2 1 0 7

样例输出

2

提示

发生两个事件时,有两种不同的情况会出现获胜方。

发生 1, 2 事件时蜀国获胜。

发生 1, 3 事件时吴国获胜。

对于 40% 的评测用例,n ≤ 500 ;

对于 70% 的评测用例,n ≤ 5000 ;

对于所有评测用例,1 ≤ n ≤ 105,1 ≤ Ai , Bi ,Ci ≤ 109 。

问题重述

魏,蜀,吴三国分别选择的所有方案最终需要满足(X>Y+Z)该条件,分别找到其可以满足的最大方案数,三国对应的3个最大方案数作为问题输出。如果都没有方案可以使三方其中一个可以获胜,则输出-1。

问题思路

对于假想赢家,要使其胜利,我们可以使用贪心的方法,如何贪心呢?以魏胜利为例:

1. 对于某个方案,如果魏国兵力大于其他两个,说明这个方案必定胜利,而且还有余下的兵力。我们先将剩余的兵力保存,便于不时之需。

2. 把n个方案都遍历一遍,找到符合(1)的方案,统计他们的数量和富余下来的兵力。而打不过的方案,将其记到本本not_want列表上,方便秋后算账。

3. 遍历完成了,魏国就把所有对自己有利的方案统统纳入麾下,然而这些方案还不能满足魏国,于是,魏国把优势在他的方案拿下后,剩下的兵力统统去协助魏国要面对的逆风局(魏国兵力不足其他两国的方案)。怎么才能使逆风局拿下的多呢,我们可以将那些不好的方案按照需要兵力大小进行从小到大排序,给他们一个个的补上,直到剩余兵力快用完,至少留一个(不能全用完,这样就不能赢了,如果最后兵力用完了,只能说明魏国和其他两国打平)。统计打赢的逆风局。

4. 将对应(1)的方案数和(3)的方案数加起来,得到魏国可以打赢需要最大的方案数。以此类推,蜀,吴两国采取同样的方法,得到他们国家最大的方案数,输出三国最大的方案数作为答案。

代码实现

1. 转换格式。问题的输入是输入三行,每行代表每个国家选择的方案所对应增加的兵力。格式如下:

  1. 输入:
  2. 5
  3. 1 2 3 4 5
  4. 5 6 7 8 9
  5. 6 5 4 3 2
  6. 表示:
  7. 5(5个方案)
  8. 魏 方案1 方案2 方案3 方案4 方案5
  9. 蜀 同上
  10. 吴 同上

将每个方案魏蜀吴三国对于增加的兵数放在一起(刚开始做的时候以为是每行表示一个方案,发现后破罐子破摔),修改格式后如下:

inf=[[魏方案1,蜀方案1,吴方案1],[魏方案2,蜀方案2,吴方案2],...]

2. 创建需要的参数。

  1. account = 0#富余的兵力
  2. ans = 0#最大可选的方案
  3. not_want = []#不足的方案统计

3. 实现问题思路(2)。

  1. for item in inf:
  2. total = item[win] - item[fail1] - item[fail2]
  3. # print(total)
  4. #if成立说明选这个方案假想winner不但会赢,还会有多出来的兵补给那些方案about假想赢家兵力不足的方案。
  5. if total > 0:
  6. account += total
  7. ans += 1
  8. #将打不过的方案先屯起来,后面用富余的兵力补充
  9. else:
  10. not_want.append(total)

3.实现问题思路(3)。

  1. not_want.sort(reverse=True)
  2. for i in not_want:
  3. if account + i <= 0:
  4. break
  5. else:
  6. account += i
  7. ans += 1

参考代码

  1. def process(inf, win, fail1, fail2):
  2. # 假想win的一方-其他两个输的,大于0则直接加入,计数+1,为什么不能等于0呢,万一全等于0不能判断其赢。
  3. # 加完后再与小于等于0的加,满足加后大于0,统计加的次数,即为该阵营赢的最大方案。
  4. account = 0#富余的兵力
  5. ans = 0#最大可选的方案
  6. not_want = []#不足的方案统计
  7. for item in inf:
  8. total = item[win] - item[fail1] - item[fail2]
  9. # print(total)
  10. #if成立说明选这个方案假想winner不但会赢,还会有多出来的兵补给那些方案about假想赢家兵力不足的方案。
  11. if total > 0:
  12. account += total
  13. ans += 1
  14. #将打不过的方案先屯起来,后面用富余的兵力补充
  15. else:
  16. not_want.append(total)
  17. #要优先考虑需要补充兵力最少的(贪心),排序,从少到多补充
  18. not_want.sort(reverse=True)
  19. for i in not_want:
  20. if account + i <= 0:
  21. break
  22. else:
  23. account += i
  24. ans += 1
  25. #没有可以获胜的情况
  26. if ans == 0:return -1
  27. return ans
  28. #输入
  29. n = int(input())
  30. inf = []
  31. a = list(map(int, input().split()))
  32. b = list(map(int, input().split()))
  33. c = list(map(int, input().split()))
  34. #结合到inf,[[方案一的a,b,c各国征兵情况],[方案二]....]
  35. for i in range(n):
  36. inf.append([a[i],b[i],c[i]])
  37. print(max(
  38. process(inf,0,1,2),
  39. process(inf,1,0,2),
  40. process(inf,2,0,1)
  41. )
  42. )

运行结果

运行地址icon-default.png?t=N7T8https://www.dotcpp.com/oj/problem3158.html

标签:
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

在线投稿:投稿 站长QQ:1888636

后台-插件-广告管理-内容页尾部广告(手机)
关注我们

扫一扫关注我们,了解最新精彩内容

搜索
排行榜