贪心算法——国王游戏

题目描述

孙悟空给花果山的小猴子们分桃子。

首先,他让每只小猴在左、右手上面分别写下一个整数,悟空自己也在左、右手上各写一个整数。

然后,让这 n 只小猴排成一排,悟空站在队伍的最前面。

排好队后,所有的小猴都会获得一些桃子,每只小猴获得的桃子数分别是:排在该小猴前面的所有猴子的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。

悟空不希望某一只小猴获得特别多的桃子,所以他想请你帮他重新安排一下队伍的顺序, 使得获得桃子最多的小猴,所获桃子尽可能的少。注意,悟空的位置始终在队伍的最前面。

输入

第一行包含一个整数 n,表示小猴数。

第二行包含两个整数 a 和 b,之间用一个空格隔开,分别表示悟空左手和右手上的整数。

接下来 n 行,每行包含两个整数 a 和 b,之间用一个空格隔开,分别表示每个小猴左手和右手上的整数。

输出

包含一个整数,表示重新排列后的队伍中获桃子最多的小猴所获得的桃子数。

输入样例

3
1 1
2 3
7 4
4 6

输出样例

2

SOURCE

NOIP 2012 国王游戏


解决思路:

这是一道典型的使用贪心算法来解决的问题

我们知道,对于任意给定的队伍顺序:若是仅交换相邻的两只猴子的话,对于前面的猴子没有影响(不改变前面的分布),对于后面的猴子也没有影响(不改变左右手的乘积)。因此,也就是说,我们通过讨论两只相邻猴子的是否交换,最后推出整只队伍的顺序,这就是最基础的思路。

数学证明:

设a1,b1为左手数字; a2,b2为右手数字

设七元组(P,a1,b1,a2,b2,sum,ans),(a1,b1)∈P,(a2,b2)∈P,sum是猴子1和猴子2前所有人左手上数字的乘积,ans是猴子1与猴子2所发钱财的最大值。
       
若选择猴子1在前面,则ans=max(sum/b1,sum*a1/b2);
       
若选择猴子2在前面,则ans=max(sum/b2,sum*a2/b1).
        
       
易知,sum/b1<sum*a2/b1,且sum/b2<sum*a1/b2。
       
∴最优解选择猴子1在前面,当sum*a1/b2<sum*a2/b1,即a1*b1<a2*b2.
          
最优解选择猴子2在前面,当sum*a2/b1<sum*a1/b2,即a2*b2<a1*b1

即得到结论:若要想使得到的ans最小,则尽量将左右手乘积小的放前面即可。

上面是对于两只相邻猴子的讨论,但实际上已经是对整个队伍的讨论。如果考虑按左右手乘积从小到大排列的排序,对任意一个无序排列,可经过有限次相邻的上述排列方法达到该排序,且有上述证明知每一次变换使结果更优(或至少不会更差),则可知按顺序由小到大时最优,及最大值最小!

代码实现:

num=int(input())+1
zong=[[0 for i in range(3)] for j in range (num-1)]
zuo,you=map(int,input().split())
cheng=zuo
for i in range (num-1):
    zong[i][0],zong[i][1]=map(int,input().split())
    zong[i][2]=zong[i][0]*zong[i][1]
xiao=1
for i in range (num-1):
    zong.sort(key=lambda x:x[2])
for i in range (num-1):
    if xiao<int(cheng/zong[i][1]):
        xiao=int(cheng/zong[i][1])
    cheng*=zong[i][0]
print(xiao)

    原文作者:贪心算法
    原文地址: https://blog.csdn.net/Eagle_hwei/article/details/80428137
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞