题目描述
小蓝正在玩一款游戏。游戏中魏蜀吴三个国家各自拥有一定数量的士兵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,相邻整数之间使用一个空格分隔。
输出格式
输出一行包含一个整数表示答案。
样例输入
31 2 22 3 21 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. 转换格式。问题的输入是输入三行,每行代表每个国家选择的方案所对应增加的兵力。格式如下:
输入:51 2 3 4 55 6 7 8 96 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