Bin-packing/Knapsack变种:离散数据分配到最低成本服务器的算法优化
一、原始算法的核心缺陷
你的原始算法本质是「贪心优先选高容量服务器,剩余容量再用更低规格服务器补」,但这个策略不成立的核心原因是:
- 三类服务器的单位容量成本不是严格线性递减,少拿1~2台高容量服务器,替换为多台低容量服务器的组合,总成本可能更低
- 你仅枚举了高容量服务器取
floor(总容量/单台容量)的固定情况,完全没有覆盖「少拿1~N台高容量服务器」的可能,自然会漏掉最优解
比如你遇到的测试用例:剩余29GB容量时,1台中+1台小成本是$140.6+$68.84=$209.44,而3台小成本仅为$206.52,少拿1台中反而更便宜,你的算法没有覆盖这种场景。
二、高效的最优求解方案
因为你只有3种服务器规格,完全不需要暴力全枚举,只需要限定枚举极小范围的高容量服务器数量即可覆盖所有可能的最优组合,时间复杂度是固定常数级,和总数据量无关。
方案逻辑
首先计算三类服务器的单位容量成本:
- 大服务器:
316.09/54 ≈ $5.853/GB(最低) - 中服务器:
140.6/24 ≈ $5.858/GB(略高于大服务器) - 小服务器:
68.84/10 = $6.884/GB(最高)
可以看出大、中服务器单位成本差距极小,小服务器明显更贵。因此最优解中,我们少拿大/中服务器的数量最多不会超过3台(少拿超过3台的话,替换为更低规格的成本必然更高),所以枚举范围可以限定为:
- 计算大服务器最多需要的数量
max_L = ceil(总容量 / 54),枚举大服务器数量从max(0, max_L - 3)到max_L - 对每一个大服务器数量,计算剩余容量
rem = max(0, 总容量 - L*54),再计算中服务器最多需要的数量max_M = ceil(rem / 24),枚举中服务器数量从max(0, max_M -3)到max_M - 剩余容量全部用小服务器补,计算当前组合的总成本
- 所有枚举的组合中取成本最低的即可
优化后代码示例
import math # 固定配置 SERVER_CONFIG = [ {'cap': 54, 'price': 316.09}, # L {'cap': 24, 'price': 140.6}, # M {'cap': 10, 'price': 68.84} # S ] PLANET_SIZES = {'S':1, 'M':1.5, 'L':2} def allocate_servers_optimal(setup): # 计算总容量 total_size = setup['S'] * PLANET_SIZES['S'] + setup['M'] * PLANET_SIZES['M'] + setup['L'] * PLANET_SIZES['L'] print(f'\n总容量需求:{total_size} GB\n') max_L = math.ceil(total_size / SERVER_CONFIG[0]['cap']) min_L = max(0, max_L - 3) min_cost = float('inf') best_combo = None # 枚举大服务器数量 for L in range(min_L, max_L + 1): rem_after_L = max(0, total_size - L * SERVER_CONFIG[0]['cap']) max_M = math.ceil(rem_after_L / SERVER_CONFIG[1]['cap']) min_M = max(0, max_M -3) # 枚举中服务器数量 for M in range(min_M, max_M +1): rem_after_M = max(0, rem_after_L - M * SERVER_CONFIG[1]['cap']) S = math.ceil(rem_after_M / SERVER_CONFIG[2]['cap']) total_price = L * SERVER_CONFIG[0]['price'] + M * SERVER_CONFIG[1]['price'] + S * SERVER_CONFIG[2]['price'] # 更新最优解 if total_price < min_cost: min_cost = total_price best_combo = {'L': L, 'M': M, 'S': S, 'total_price': round(total_price, 2)} return best_combo
这个方案最多只需要枚举4*4=16种组合,哪怕总容量到10万GB也能毫秒级返回结果,且完全覆盖所有可能的最优解。
三、是否需要全枚举所有组合?
完全不需要。你当前的暴力枚举方案是典型的过度计算,因为服务器规格少、单位成本差距固定,只需要枚举极小范围的高容量服务器数量就能覆盖所有最优可能,性能不会随数据量增长而下降。
内容的提问来源于stack exchange,提问作者AlexZ
相关产品推荐
相关产品推荐

