如何解决组合太多
嗨,我正在尝试生成所有可能的工人到建筑物的组合。 (让我解释一下我的场景):
我正在玩《我的世界》MineColonies。在这个模组中,你有殖民者,他们可以在建筑物中分配工作。这些工人拥有技能和分配给他们的分数。 (例如敏捷:20,力量:5 等)并且当分配到技能与之相称的殖民者时,建筑物的工作会得到更好的执行...
所以我创建了一个包含所有工人和建筑物的数据库,并希望优化哪些工人在哪些建筑物内工作。
buildings_dict = {1: ['Strength','Focus'],2: ['Adaptability','Athletics'],3: ['KNowledge','Dexterity'],4: ['Adaptability','KNowledge'],6: ['Stamina',5: ['Athletics','Stamina'],7: ['Focus','Agility'],8: ['Dexterity','Creativity'],9: ['Strength',10: ['Adaptability',11: ['Agility','Adaptability'],12: ['Mana',13: ['Strength',14: ['Athletics','Strength'],15: ['Creativity',16: ['KNowledge','Mana'],17: ['Agility','Adaptability']}
workers_dict = {3: {'Mana': 30,'Focus': 1,'Agility': 3,'Stamina': 3,'KNowlege': 30,'Strenght': 8,'Athletics': 13,'Dexterity': 6,'Creativity': 10,'Adaptability': 10,'Intelligence': 10},4: {'Mana': 29,'Focus': 32,'Agility': 22,'Stamina': 28,'KNowlege': 21,'Strenght': 30,'Athletics': 20,'Dexterity': 31,'Creativity': 31,'Adaptability': 8,'Intelligence': 18},5: {'Mana': 13,'Agility': 9,'Stamina': 27,'KNowlege': 9,'Strenght': 13,'Athletics': 15,'Dexterity': 21,'Creativity': 16,'Adaptability': 13,'Intelligence': 28},6: {'Mana': 17,'Focus': 14,'Agility': 10,'Stamina': 17,'KNowlege': 13,'Strenght': 5,'Athletics': 10,'Dexterity': 15,'Creativity': 1,'Adaptability': 11,'Intelligence': 4},7: {'Mana': 1,'Focus': 8,'Agility': 6,'KNowlege': 11,'Strenght': 17,'Athletics': 30,'Dexterity': 1,'Creativity': 5,'Intelligence': 5},8: {'Mana': 6,'Agility': 12,'Stamina': 30,'KNowlege': 20,'Strenght': 15,'Dexterity': 9,'Creativity': 17,'Adaptability': 30,'Intelligence': 19},9: {'Mana': 5,'Focus': 7,'Agility': 19,'Stamina': 5,'KNowlege': 22,'Strenght': 18,'Athletics': 26,'Dexterity': 10,'Creativity': 24,'Adaptability': 20,'Intelligence': 22},10: {'Mana': 8,'Focus': 12,'Agility': 27,'KNowlege': 17,'Strenght': 1,'Athletics': 5,'Creativity': 7,'Adaptability': 29,'Intelligence': 1},11: {'Mana': 1,'Focus': 4,'Agility': 5,'KNowlege': 16,'Strenght': 11,'Athletics': 28,'Dexterity': 11,'Adaptability': 12,12: {'Mana': 7,'Agility': 17,'Stamina': 25,'KNowlege': 23,'Strenght': 4,'Athletics': 8,'Dexterity': 26,'Creativity': 15,13: {'Mana': 2,'Stamina': 21,'KNowlege': 24,'Creativity': 12,14: {'Mana': 9,'Focus': 16,'Agility': 14,'KNowlege': 14,'Strenght': 24,'Creativity': 19,'Adaptability': 23,15: {'Mana': 23,'Focus': 15,'Stamina': 12,'Strenght': 12,'Dexterity': 29,'Adaptability': 19,'Intelligence': 12},17: {'Mana': 21,'Focus': 23,'Agility': 30,'Stamina': 18,'KNowlege': 27,'Strenght': 7,'Adaptability': 22,18: {'Mana': 11,'Focus': 11,'Agility': 4,'Stamina': 7,'KNowlege': 28,'Dexterity': 28,'Creativity': 13,'Intelligence': 30},19: {'Mana': 11,20: {'Mana': 15,'Focus': 20,'Agility': 28,'Stamina': 22,'KNowlege': 18,'Athletics': 23,'Dexterity': 19,'Creativity': 20,'Adaptability': 27,'Intelligence': 20},21: {'Mana': 30,'Strenght': 3,'Athletics': 6,'Dexterity': 17,'Creativity': 4,22: {'Mana': 9,'Focus': 10,'Stamina': 26,'KNowlege': 1,'Adaptability': 14,'Intelligence': 16},23: {'Mana': 4,'KNowledge': 21,'Strength': 25,'Athletics': 12,'Dexterity': 23,'Creativity': 26,'Adaptability': 21,24: {'Mana': 1,'Agility': 18,'Stamina': 24,'KNowledge': 25,'Strength': 20,'Athletics': 9,'Dexterity': 14,'Intelligence': 7},25: {'Mana': 12,'Focus': 13,'Agility': 21,'Stamina': 23,'KNowledge': 11,'Strength': 16,'Athletics': 18,'Dexterity': 24,26: {'Mana': 10,'KNowledge': 17,'Strength': 24,'Adaptability': 5,27: {'Mana': 11,'KNowledge': 15,'Athletics': 17,'Dexterity': 12,'Intelligence': 9},28: {'Mana': 7,'Focus': 21,'KNowledge': 14,'Strength': 15,'Dexterity': 16,'Creativity': 2,29: {'Mana': 12,'Focus': 25,'Agility': 29,'Stamina': 6,'KNowledge': 7,'Strength': 10,'Athletics': 14,'Creativity': 6,'Intelligence': 29},30: {'Mana': 21,'Focus': 17,'Agility': 8,'KNowledge': 22,'Strength': 22,'Dexterity': 13,'Adaptability': 24,'Intelligence': 13}}
抱歉,代码块太长,是的,我意识到 ID 不一定正确(希望使其可重现)。
所以我使用 itertools.permutations
将所有工人组合到建筑物中:
import itertools
workers_ls = list(workers_dict.keys())
combinations = list(itertools.permutations(workers_ls,len(buildings_dict))
(我打算在之后对组合进行评分)
这显然从未完成运行,因为它类似于 27! = 1×10²⁸。 我想知道是否有其他解决方案可以解决我的问题,或者是否有一种无需经过所有组合即可确定最佳解决方案的方法。 (我愿意用其他编码语言工作)
谢谢!
解决方法
我假设您想最大化总产量的总和。例如,当没有分配工人时,总产量为零(或某个不依赖于工人分配的常数)。如果您将具有 Agility
2 和 Focus
3 的工人与具有属性 [Agility,Focus]
的建筑物配对,则将 2+3=5
添加到总产量中。
像这样的问题通常可以通过线性规划来解决。我将使用 pulp
来帮助制定线性规划问题。我还建议您查看 Julia
包 JuMP
。
计算总产量的实际规则可能更复杂。如果 (1) 可以定义生产矩阵的一些模拟,并且 (2) 总产量可以表示为(工人、建筑)对的产量之和,您仍然可以使用线性规划。
这里有两种方法可以解决这个问题。第一个允许每个建筑物有多个工人,第二个不允许。
设置
import pandas as pd
import numpy as np
# !pip install pulp
import pulp
df_buildings = pd.DataFrame(buildings_dict).T
df_workers = pd.DataFrame(workers_dict).T
# there are a few typos,e.g. Strenght vs. Strength and Knowlege vs. Knowledge
# let's fix this first
df_workers.Knowledge.fillna(df_workers.Knowlege,inplace=True)
df_workers.Strength.fillna(df_workers.Strenght,inplace=True)
del df_workers["Strenght"],df_workers["Knowlege"]
# fixing some notation
workers = df_workers.index.tolist() # list of workers
buildings = df_buildings.index.tolist() # list of building
# next,we define production matrix
# production[i,j] will contain the productivity of
# worker i when assigned to building j
# you could vectorize this step,though it seems fast enough here
production = pd.DataFrame(index=workers,columns=buildings)
for i in df_workers.index:
for j in df_buildings.index:
production.loc[i,j] = df_workers.loc[i,df_buildings.loc[j]].sum()
print(production.head())
# 1 2 3 4 6 5 7 8 9 10 11 12 13 14 15 16 17
# 3 9 23 36 40 16 16 4 16 9 13 13 60 11 21 16 60 13
# 4 62 28 52 29 48 48 54 62 62 36 30 50 58 50 62 50 30
# 5 14 28 30 22 42 42 10 37 14 40 22 22 40 28 37 22 22
# 6 19 21 28 24 27 27 24 16 19 28 21 30 22 15 16 30 21
# 7 25 41 12 22 57 57 14 6 25 38 17 12 44 47 6 12 17
每栋楼允许多名工人
prob = pulp.LpProblem("MineColoniesProblem",pulp.LpMaximize)
# in the solved problem,assignment[i,j] == 1 whenever i is assigned to j
assignment = pulp.LpVariable.dicts("Assignment",(workers,buildings),cat="Binary")
# our objective is to maximize the sum of production
prob += sum(assignment[i][j] * production.loc[i,j]
for i in workers for j in buildings)
# each worker can be assigned to at most one building:
for i in workers:
prob += sum(assignment[i][j] for j in buildings) <= 1
prob.solve()
# make sure that we got an optimal solution
assert prob.status == 1
# generically,we get an integer solution
assignment_dict = {i: j for i in workers for j in buildings
if assignment[i][j].varValue == 1}
print(f"Total production is {prob.objective.value()}") # 1401
# here is the the solution
# assignment_dict_saved = {3: 12,4: 1,5: 5,6: 16,7: 5,8: 6,9: 2,10: 17,11: 6,12: 10,13: 4,14: 6,15: 3,17: 7,18: 3,19: 3,20: 11,21: 12,22: 17,23: 15,24: 4,25: 10,26: 13,27: 9,28: 7,29: 7,30: 2}
每栋楼最多一名工人
prob = pulp.LpProblem("MineColoniesProblem",j]
for i in workers for j in buildings)
# each worker can be assigned to at most one building:
for i in workers:
prob += sum(assignment[i][j] for j in buildings) <= 1
# each building has at most one worker
for j in buildings:
prob += sum(assignment[i][j] for i in workers) <= 1
prob.solve()
# make sure that we got an optimal solution
assert prob.status == 1
# generically,we get an integer solution
assignment_dict = {i: j for i in workers for j in buildings
if assignment[i][j].varValue == 1}
# assignment_dict_saved = {3: 16,4: 9,8: 2,10: 11,14: 14,19: 8,20: 17,27: 1,29: 7}
print(f"Total production is {prob.objective.value()}") # 929
我们可以看到,当我们允许每个建筑物有多个工人时,总产量会更高。这是意料之中的,因为最大化问题的约束较少。
我们还可以将优化的生产与随机分配工人到建筑物时的生产进行比较。垂直线对应于最佳生产。看起来我们做得很好。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。