ZOJ 2109 FatMouse‘ Trade(python版解答)


题目链接

https://zoj.pintia.cn/problem-sets/91827364500/problems/91827365608

背景

胖老鼠准备了M磅的猫粮,准备与守卫着他最喜欢的食物爪哇豆仓库的猫进行交易。仓库有N个房间。第i个房间里有J磅的爪哇豆,需要F磅的猫粮。胖老鼠不必用房间里的所有爪哇豆来交换,相反,如果他支付F[i]*a%磅的猫粮,他可能会得到J[i]*a%磅爪哇豆。这里a是一个实数。现在他给你布置了这个作业:告诉他他能获得的JavaBean的最大数量。

输入

输入由多个测试用例组成。每个测试用例以一行开始,该行包含两个非负整数M和N。然后N行紧随其后,每行分别包含两个负整数J[i]和F[i]。最后一个测试用例后面是两个-1。所有整数都不大于1000。

输出

对于每个测试用例,在一行中打印一个精确到小数点后3位的实数,这是FatMouse可以获取的JavaBean的最大数量。

输入示例

5 3
7 2
4 3
5 2
20 3
25 18
24 15
15 10
-1 -1

输出示例

13.333
31.500

思路

解答这道题要用到贪心算法,要用最少的猫粮(F)换到最多的爪哇豆(J)。这样,就需要计算每个房间中爪哇豆和猫粮的比值(v = J / F),然后从大到小排序, 接着在排好序的房间中依次支付猫粮换取爪哇豆,直到达到准备的猫粮总数M为止。然而,由于对比值v进行排序的时候,F和J也要联动排序,所以如何达到较高的排序效率,是这道题的关键。

使用3个数组分别填充F、J、v的数据然后依次排序,效率是不达标的,一个有效的解决方法是用对象的数组。对象node表示某一个具体的仓库房间,其中应该包括f, j, v 3个成员,f表示该房间中猫粮的数量,j表示该房间中爪哇豆的数量,v则表示f/v的比值。其python代码如下所示:

class node:
	def __init__( self, j: float = 0.0, f: float = 0.0, v: float = 0.0 ): 
		self.j = j
		self.f = f
		self.v = v

接下来需要建立一个node对象的数组。由于题目中已经明说所有整数不大于1000,所以数组容量上限可以预订为1000,代码如下:

a = [ node() for _ in range( 1000 ) ]

如何对这个对象数组进行排序是这道题的难点。普通的排序算法如冒泡排序、快速排序效率都不高,难以通过测试,但事实上,只要用python sort命令的内置排序算法即可。python的内置排序算法是Timsort,是世界上最快的排序算法,综合性能是最好的1。但是我们希望在sort对象数组时按照元素v从大到小降序排序,这如何实现呢?回答这个问题,我们要了解一下sort命令的参数,python list.sort()命令的参数如下:

sort(self, /, *, key=None, reverse=False)
# 按升序排序列表并返回None。排序会改变列表本身,并且保持原列表中两个相等元素的顺序
# 如果给定了键函数,则根据函数值对每个列表项应用一次并对其进行排序。
# 反转标志可以设置为按降序排序。

根据给出的解释,我们需要编写一个键函数,函数的返回值就是node对象中v的值,然后在sort中应用该键函数,再加上reverse,就可以实现node对象数组按元素v的值从大到小排序,代码如下:

# 键函数
def sort_fun( x1 ):
	return(x1.v)
# 在主函数中的sort命令中应用此键函数
a.sort( key=sort_fun, reverse=True )

python版解答

这道题在网上已经有很多解答,但python版本的解答还没有。在这里附上python版本AC的代码:

import sys
class node:
	def __init__( self, j: float = 0.0, f: float = 0.0, v: float = 0.0 ): 
		self.j = j
		self.f = f
		self.v = v
	def print_node( self ):
		print( "{} {} {}".format( self.j, self.f, self.v ) )	
		
def sort_fun( x1 ):
	return(x1.v)	
			
def main():
	infile = sys.stdin
	while True:
		a = [ node() for _ in range( 1000 ) ] # 所有整数不会大于1000,所以一个案例最多1000个节点。
		x = infile.readline().strip().split()
		M, N = int( x[ 0 ] ), int( x[ 1 ] )
		if M == -1 and N == -1:
			break
		total = 0.0
		# 读入矩阵
		for i in range( N ):
			x = infile.readline().strip().split()
			j, f = float( x[ 0 ] ), float( x[ 1 ] )
			if f > 0:
				a[i].j, a[i].f, a[i].v = j, f, j / f
			else:
				a[i].j, a[i].f, a[i].v = j, f, 10001.0
		
		a.sort( key=sort_fun, reverse=True )

		for i in range( N ):
			if M > a[ i ].f:
				total += a[ i ].j
				M -= a[ i ].f
			elif M == a[ i ].f:
				total += a[ i ].j
				M -= a[ i ].f	
			else:			
				total += a[ i ].v * M
				break
		print( "{:.3f}".format( total ) )	
	return( 0 )
		
main()	

参考资料

  1. python中涉及到的对象排序 - 神之凉皮 - 博客园
  2. 详解Python列表(list)的方法sort()的第一个参数key【简单清晰明了的讲解】_昊虹AI笔记的博客-CSDN博客_python列表sort中的key参数科
  3. ZOJ 2109 FatMouse’ Trade(贪心 - 背包问题)_Sun66882的博客-CSDN博客
  4. 从用python做zoj1011发生Non-zero Exit Code错误说起
  5. 如何利用python语言实现对象数组_HenrySmale的博客-CSDN博客_python 对象数组
  6. FatMouse’ Trade(贪心)_幽影相随的博客-CSDN博客_fatmouse’ trade
  7. 题目为FatMouse'trade 的一个简单贪心题,测试数据都是对的,但是为什么一直ac不了?麻烦大神们看看啊~~ - C语言论坛 - 编程论坛

  1. 世界上最快的排序算法——Timsort_xlj3的博客-CSDN博客_最快的排序算法 ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

下唐人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值