蓝桥杯笔记-2023年第十四届省赛真题-三国游戏(Python)
后台-插件-广告管理-内容页头部广告(手机) |
题目描述
小蓝正在玩一款游戏。游戏中魏蜀吴三个国家各自拥有一定数量的士兵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. 转换格式。问题的输入是输入三行,每行代表每个国家选择的方案所对应增加的兵力。格式如下:
- 输入:
- 5
- 1 2 3 4 5
- 5 6 7 8 9
- 6 5 4 3 2
- 表示:
- 5(5个方案)
- 魏 方案1 方案2 方案3 方案4 方案5
- 蜀 同上
- 吴 同上
将每个方案魏蜀吴三国对于增加的兵数放在一起(刚开始做的时候以为是每行表示一个方案,发现后破罐子破摔),修改格式后如下:
inf=[[魏方案1,蜀方案1,吴方案1],[魏方案2,蜀方案2,吴方案2],...]2. 创建需要的参数。
- account = 0#富余的兵力
- ans = 0#最大可选的方案
- not_want = []#不足的方案统计
3. 实现问题思路(2)。
- for item in inf:
- total = item[win] - item[fail1] - item[fail2]
- # print(total)
- #if成立说明选这个方案假想winner不但会赢,还会有多出来的兵补给那些方案about假想赢家兵力不足的方案。
- if total > 0:
- account += total
- ans += 1
- #将打不过的方案先屯起来,后面用富余的兵力补充
- else:
- not_want.append(total)
3.实现问题思路(3)。
- not_want.sort(reverse=True)
- for i in not_want:
- if account + i <= 0:
- break
- else:
- account += i
- ans += 1
参考代码
- def process(inf, win, fail1, fail2):
- # 假想win的一方-其他两个输的,大于0则直接加入,计数+1,为什么不能等于0呢,万一全等于0不能判断其赢。
- # 加完后再与小于等于0的加,满足加后大于0,统计加的次数,即为该阵营赢的最大方案。
- account = 0#富余的兵力
- ans = 0#最大可选的方案
- not_want = []#不足的方案统计
- for item in inf:
- total = item[win] - item[fail1] - item[fail2]
- # print(total)
- #if成立说明选这个方案假想winner不但会赢,还会有多出来的兵补给那些方案about假想赢家兵力不足的方案。
- if total > 0:
- account += total
- ans += 1
- #将打不过的方案先屯起来,后面用富余的兵力补充
- else:
- not_want.append(total)
- #要优先考虑需要补充兵力最少的(贪心),排序,从少到多补充
- not_want.sort(reverse=True)
- for i in not_want:
- if account + i <= 0:
- break
- else:
- account += i
- ans += 1
- #没有可以获胜的情况
- if ans == 0:return -1
- return ans
- #输入
- n = int(input())
- inf = []
- a = list(map(int, input().split()))
- b = list(map(int, input().split()))
- c = list(map(int, input().split()))
- #结合到inf,[[方案一的a,b,c各国征兵情况],[方案二]....]
- for i in range(n):
- inf.append([a[i],b[i],c[i]])
- print(max(
- process(inf,0,1,2),
- process(inf,1,0,2),
- process(inf,2,0,1)
- )
- )
运行结果
运行地址https://www.dotcpp.com/oj/problem3158.html
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。
在线投稿:投稿 站长QQ:1888636
后台-插件-广告管理-内容页尾部广告(手机) |