简体   繁体   English

纸浆:如何构造这个工厂覆盖率问题

[英]PuLP: How to structure this factory coverage problem

Struggling to formulate the objective function to the following MIP scenario in PuLP.努力将目标 function 制定为纸浆中的以下 MIP 场景。

Each city is populated by N number of people.每个城市都有 N 人居住。
Each factory location can facilitate a set of cities.每个工厂位置可以促进一组城市。
Minimize the number factories to open, such that the number of people facilitated is >= 4000尽量减少开办工厂的数量,使便利的人数>= 4000

My main issue comes from the fact that different factories can service the same cities.我的主要问题来自于不同的工厂可以为同一个城市服务。 So it isn't fair to sum the servicable population population of each factory and consider them seperately.因此,将每个工厂的可服务人口总数相加并单独考虑是不公平的。

cities = ['London', 'Paris', 'Berlin', 'Amsterdam', 'Vienna', 'Prague']
factories = ['A', 'B', 'C', 'D']

city_populations = {'London': 898, 'Paris': 222, 'Berlin': 767, 'Amsterdam': 111, 'Vienna': 854, 'Prague': 908}

factories_service = {'A': ['London', 'Prague'], 'B': ['London', 'Paris', 'Vienna'], 'C': ['Amsterdam', 'Vienna', 'Prague'], 'D': ['London', 'Vienna', 'Prague']}

This is what I have at the moment but it is incorrect as it just picks the largest cities with no regard for population overlap.这是我目前所拥有的,但这是不正确的,因为它只是选择了最大的城市,而不考虑人口重叠。

prob = pl.LpProblem("Factory Coverage",pl.LpMinimize)
​
decision_vars = pl.LpVariable.dicts("Factories", factories, cat='Binary')
​
prob += pl.lpSum(decision_vars)
prob += pl.lpSum([sum([city_populations[x] for x in factories_service[i]])*decision_vars[i] for i in factories]) >= 4000
​
​
prob.solve()

Output: Output:
Factories_A, 0.0工厂_A,0.0
Factories_B, 1.0工厂_B, 1.0
Factories_C, 0.0工厂_C,0.0
Factories_D, 1.0工厂_D, 1.0

The main problem is that you are double-counting the population.主要问题是您重复计算了人口。 If two factories service the same city, and both are built, the population of that city should be accounted as serviced only once.如果两个工厂服务于同一个城市,并且都建成了,那么该城市的人口应该只计算一次服务。

You can accomplish that by creating another set of binary variables for the cities, indicating if the city is serviced or not.您可以通过为城市创建另一组二进制变量来完成此操作,指示该城市是否得到服务。 And then add logic that determines that a city is serviced only if there is a factory that services it.然后添加逻辑,确定只有在有工厂为其提供服务的情况下才能为城市提供服务。

Another minor problem you have is that you don't have 4000 citizens in your entire model since sum(city_populations.values()) == 3760您遇到的另一个小问题是您的整个 model 中没有 4000 名公民,因为sum(city_populations.values()) == 3760

This is an example of how you could solve this problem, though it is not the most efficient implementation:这是如何解决此问题的示例,尽管它不是最有效的实现:

prob = pl.LpProblem("Factory Coverage",pl.LpMinimize)

factories_vars = pl.LpVariable.dicts("Factories", factories, cat='Binary')
cities_vars = pl.LpVariable.dicts("Cities", cities, cat='Binary')

# Objective function
prob += pl.lpSum(factories_vars)
# Population served is greater than 4000
prob += pl.lpSum([city_populations[c]*cities_vars[c] for c in cities]) >= 2000
# City is served only if there is a factory that serves it
bigM = len(factories)
for c in cities:
    prob +=  bigM * cities_vars[c] >= pl.lpSum([factories_vars[f] for f in factories_vars if c in factories_service[f]])
    prob +=  cities_vars[c] <= pl.lpSum([factories_vars[f] for f in factories_vars if c in factories_service[f]])

prob.solve()

Result:结果:

for f in factories_vars:
    print(f, factories_vars[f].value())
for c in cities_vars:
    print(c, cities_vars[c].value())

A 0.0
B 0.0
C 0.0
D 1.0
London 1.0
Paris 0.0
Berlin 0.0
Amsterdam 0.0
Vienna 1.0
Prague 1.0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM