能具体说下么。一组什么样的数据?数字组合怎么样算接近固定值?
根据楼主的回复,大概理解了一下需求,做出这个样子。每次分配比较随机,可以选择增加次数来尽可能分配出最大符合要求的比例。参数都已提取出,数组可以自己去定义,也可以随机生成,楼主按需调整试下吧。
# -*- coding: utf-8 -*-
import random
import copy
class Group(object):
def __init__(self):
self.arr = []
def insert(self, num):
sum_ = sum(self.arr)
add_abs = abs(sum_ + num - NEAR)
if self.checked():
return False
if abs(sum_ - NEAR) > add_abs:
self.arr.append(num)
return True
else:
return False
def checked(self):
if abs(sum(self.arr) - NEAR) > ALLOW_NEAR:
return False
else:
return True
def pop_checked(self):
"""是否可以抛出一个数也符合要求"""
p = None
p_index = None
self.arr.sort()
for index, i in enumerate(self.arr):
if abs(sum(self.arr) - NEAR - i) <= ALLOW_NEAR:
p = i
p_index = index
break
if p is not None:
# print('{}中弹出{},index:{}'.format(self.arr, p, p_index))
self.arr.pop(p_index)
return p
def __str__(self):
return '{}\t\t{}'.format(self.arr, sum(self.arr))
def generate_arr():
"""
数组生成
:return:
"""
arr = [random.uniform(MIN, MAX) for i in range(NUM)]
# 打乱
random.shuffle(arr)
# print(arr)
return arr
def add_group(num, all_group):
"""
新增一组
:param num: 加入的第一个数字
:param all_group: 所有组
:return:
"""
one_group = Group()
one_group.insert(num)
all_group.append(one_group)
def loop_assigned(arr, all_group):
"""
进行一轮循环分配
:param arr:
:param all_group:
:return:
"""
while arr:
num = arr.pop()
# 没有任何一个组时直接创一组新的
if not all_group:
add_group(num, all_group)
else:
# 现有组中尝试插入,若没有符合的组,则该数字放入新组
for one_group in all_group:
if one_group.insert(num):
break
else:
add_group(num, all_group)
def check_and_reload(all_group, old_arr):
"""
检查以及重置
:param all_group: 所有组
:param old_arr: 旧数组
:return:
"""
new_arr = []
need_del = []
# 取出不符合的,并尝试抛出一数字使得组也符合要求
for index, one_group in enumerate(all_group):
if not one_group.checked():
need_del.append(index)
new_arr.extend(one_group.arr)
else:
p = one_group.pop_checked()
if p is not None:
new_arr.append(p)
need_del.sort(reverse=True)
for i in need_del:
all_group.pop(i)
# 检查新数组和旧数组是否一致
new_arr_ = copy.copy(new_arr)
old_arr_ = copy.copy(old_arr)
new_arr_.sort()
old_arr_.sort()
if new_arr_ == old_arr_:
return True
return new_arr
def check_all(all_group):
"""
检查全部
:param all_group:
:return:
"""
all_num = len(all_group)
success_num = 0
for one_group in all_group:
if one_group.checked():
success_num += 1
return success_num / all_num
def printf(all_group):
"""
格式化输出
:param all_group: 所有组
:return:
"""
assigned_num = 0
for index, one_group in enumerate(all_group):
print('组{}\t\t{}'.format(index, one_group))
assigned_num += len(one_group.arr)
print('已分配:{}'.format(assigned_num))
def entry(arr):
"""
入口
:param arr:
:return:
"""
all_group = []
while True:
old_arr = copy.copy(arr)
loop_assigned(arr, all_group)
arr = check_and_reload(all_group, old_arr)
if arr is True:
loop_assigned(old_arr, all_group)
break
if not arr:
break
random.shuffle(arr)
return all_group
if __name__ == '__main__':
# 范围
MIN, MAX = 0, 11
# 数量
NUM = 40
# 每组之和接近值
NEAR = 12
# 允许的最大误差
ALLOW_NEAR = 0.5
# 最大尝试次数
MAX_TRY = 1000
# 数组设置使用循环(也可以自定义)
ARR = generate_arr()
print(ARR)
# ARR = [4.953407828957589, 4.140340410658476, 5.259521935483457, 7.949343846104568, 9.352910928537101,
# 0.9401237055906155, 8.886567109127252, 8.582804063607739, 8.909789082692823, 0.9371141041309015,
# 5.08028735167332, 4.787531539932322, 6.211072877578918, 8.23308481869395, 3.4715979823454672,
# 10.194693316334547, 2.1517346171926657, 2.942843349547707, 8.078291496154526, 6.4305952425745385,
# 9.551689941272537, 8.020144381125009, 0.806307266267717, 3.2504424916275134, 4.245998753673247,
# 1.18379976915499, 4.705039778972266, 5.755751614164035, 0.5969359910628516, 9.603256761119983,
# 5.180673714904525, 7.402241808520505, 1.1956881175615912, 9.447177065332923, 5.808131356683512,
# 4.710040782844348, 8.77972417272467, 3.437574446881425, 7.204353799356635, 8.982024068919952]
optimal_rate = 0
optimal_loop = None
for i in range(MAX_TRY):
one_try_all_group = entry(copy.copy(ARR))
rate = round(check_all(one_try_all_group), 4)
if rate > optimal_rate:
optimal_rate = rate
optimal_loop = one_try_all_group
# print('已尝试{}次'.format(i + 1))
printf(optimal_loop)
print('当前最优解比例{}%'.format(optimal_rate * 100))