OR-Tools 解决的问题类型:
Linear optimizationConstraint optimizationMixed-integer optimizationBin packingNetwork flowsAssignmentSchedulingRouting网络流:
计算机科学中的许多问题可以通过由节点和节点之间的链接组成的图形来表示。例如网络流量问题,它涉及通过网络(如铁路系统)运输货物或材料。可以通过节点为城市且其弧线是城市之间的铁路线的图形来表示网络流。
网络流中的一个关键约束是每个弧线都有一个容量 - 可以在固定的时间内跨弧传输的最大量。
最大流量问题是确定在容量限制下,可跨网络中所有弧线传输的最大总流量。
网络流问题的示例,并演示如何解决这些问题:最大流量和最低成本流
最大流量:
例如运输网络
材料从节点 0(源)运送到节点 4(接收器)。弧线旁边的数字是它们的容量- 圆弧的容量是可以在固定的时间内在圆弧上传输的最大量。能力是问题的约束因素。例如node0-node1容量是20,node3到node2容量5
# Define three parallel arrays: start_nodes, end_nodes, and the capacities # between each pair. For instance, the arc from node 0 to node 1 has a # capacity of 20. start_nodes = [0, 0, 0, 1, 1, 2, 2, 3, 3] end_nodes = [1, 2, 3, 2, 4, 3, 4, 2, 4] capacities = [20, 30, 10, 40, 30, 10, 20, 5, 20] from __future__ import print_function from ortools.graph import pywrapgraph def main(): """MaxFlow simple interface example.""" # Define three parallel arrays: start_nodes, end_nodes, and the capacities # between each pair. For instance, the arc from node 0 to node 1 has a # capacity of 20. start_nodes = [0, 0, 0, 1, 1, 2, 2, 3, 3] end_nodes = [1, 2, 3, 2, 4, 3, 4, 2, 4] capacities = [20, 30, 10, 40, 30, 10, 20, 5, 20] # Instantiate a SimpleMaxFlow solver. max_flow = pywrapgraph.SimpleMaxFlow() # Add each arc. for i in range(0, len(start_nodes)): max_flow.AddArcWithCapacity(start_nodes[i], end_nodes[i], capacities[i]) # Find the maximum flow between node 0 and node 4. if max_flow.Solve(0, 4) == max_flow.OPTIMAL: print('Max flow:', max_flow.OptimalFlow()) print('') print(' Arc Flow / Capacity') for i in range(max_flow.NumArcs()): print('%1s -> %1s %3s / %3s' % ( max_flow.Tail(i), max_flow.Head(i), max_flow.Flow(i), max_flow.Capacity(i))) print('Source side min-cut:', max_flow.GetSourceSideMinCut()) print('Sink side min-cut:', max_flow.GetSinkSideMinCut()) else: print('There was an issue with the max flow input.') if __name__ == '__main__': main()最低成本问题:与最大流量问题密切相关的是最小成本(最小成本) 流问题,其中图中每个弧线都有跨其运输物料的单位成本。问题是找到总成本最少的流程。最小成本流问题还具有特殊节点,称为供给节点或需求节点。
物料从供应节点运输到需求节点。
在供应节点上,正量 (供给) 添加到流中。例如,供应可以表示该节点的生产。在需求节点上,负量(需求)从流中消失。例如,需求可以表示该节点的消耗量。为方便起见,我们假设除供给或需求节点以外的所有节点的供给(和需求)为零。
对于最小成本流问题,我们有以量保护规则,其中考虑到供应和需求:
节点流出的总流量减去流入该节点的总流量等于该节点上的供给。
下图显示了最小成本流问题。弧线标有数字对:第一个数字是容量,第二个数字是成本。节点旁边的括号中的数字表示供应或需求。节点 0 是电源节点 20,节点 3 和 4 是需求节点,需求量为 -5 和 -15。
# Define four parallel arrays: start_nodes, end_nodes, capacities, and unit costs # between each pair. For instance, the arc from node 0 to node 1 has a # capacity of 15 and a unit cost of 4. start_nodes = [ 0, 0, 1, 1, 1, 2, 2, 3, 4] end_nodes = [ 1, 2, 2, 3, 4, 3, 4, 4, 2] capacities = [15, 8, 20, 4, 10, 15, 4, 20, 5] unit_costs = [ 4, 4, 2, 2, 6, 1, 3, 2, 3] # Define an array of supplies at each node. supplies = [20, 0, 0, -5, -15] from __future__ import print_function from ortools.graph import pywrapgraph def main(): """MinCostFlow simple interface example.""" # Define four parallel arrays: start_nodes, end_nodes, capacities, and unit costs # between each pair. For instance, the arc from node 0 to node 1 has a # capacity of 15 and a unit cost of 4. start_nodes = [ 0, 0, 1, 1, 1, 2, 2, 3, 4] end_nodes = [ 1, 2, 2, 3, 4, 3, 4, 4, 2] capacities = [15, 8, 20, 4, 10, 15, 4, 20, 5] unit_costs = [ 4, 4, 2, 2, 6, 1, 3, 2, 3] # Define an array of supplies at each node. supplies = [20, 0, 0, -5, -15] # Instantiate a SimpleMinCostFlow solver. min_cost_flow = pywrapgraph.SimpleMinCostFlow() # Add each arc. for i in range(0, len(start_nodes)): min_cost_flow.AddArcWithCapacityAndUnitCost(start_nodes[i], end_nodes[i], capacities[i], unit_costs[i]) # Add node supplies. for i in range(0, len(supplies)): min_cost_flow.SetNodeSupply(i, supplies[i]) # Find the minimum cost flow between node 0 and node 4. if min_cost_flow.Solve() == min_cost_flow.OPTIMAL: print('Minimum cost:', min_cost_flow.OptimalCost()) print('') print(' Arc Flow / Capacity Cost') for i in range(min_cost_flow.NumArcs()): cost = min_cost_flow.Flow(i) * min_cost_flow.UnitCost(i) print('%1s -> %1s %3s / %3s %3s' % ( min_cost_flow.Tail(i), min_cost_flow.Head(i), min_cost_flow.Flow(i), min_cost_flow.Capacity(i), cost)) else: print('There was an issue with the min cost flow input.') if __name__ == '__main__': main() Minimum cost: 150 Arc Flow / Capacity Cost 0 -> 1 12 / 15 48 0 -> 2 8 / 8 32 1 -> 2 8 / 20 16 1 -> 3 4 / 4 8 1 -> 4 0 / 10 0 2 -> 3 12 / 15 12 2 -> 4 4 / 4 12 3 -> 4 11 / 20 22 4 -> 2 0 / 5 0最低成本求解线性赋值问题
# Define the directed graph for the flow. start_nodes = [0, 0, 0, 0] + [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4] + [5, 6, 7, 8] end_nodes = [1, 2, 3, 4] + [5, 6, 7, 8, 5, 6, 7, 8, 5, 6, 7, 8, 5, 6, 7, 8] + [9, 9, 9, 9] capacities = [1, 1, 1, 1] + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + [1, 1, 1, 1 ] costs = ([0, 0, 0, 0] + [90, 76, 75, 70, 35, 85, 55, 65, 125, 95, 90, 105, 45, 110, 95, 115] + [0, 0, 0, 0]) source = 0 sink = 9 tasks = 4 supplies = [4, 0, 0, 0, 0, 0, 0, 0, 0, -4]六名工人被分成两个小组。问题是为工作人员分配四个任务,以便工作负荷在团队之间保持平等平衡,也就是说,每个团队执行其中两个任务。工作点对应于节点 1 - 6。A 组由工作人员 1、3 和 5 组成,B 组由工作人员 2、4 和 6 组成。任务编号为 7 - 10。每个团队最多可以执行两项任务。
from __future__ import print_function from ortools.graph import pywrapgraph import time def main(): min_cost_flow = pywrapgraph.SimpleMinCostFlow() # Define the directed graph for the flow. team_A = [1, 3, 5] team_B = [2, 4, 6] start_nodes = ([0, 0] + [11, 11, 11] + [12, 12, 12] + [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6] + [7, 8, 9, 10]) end_nodes = ([11, 12] + team_A + team_B + [7, 8, 9, 10, 7, 8, 9, 10, 7, 8, 9, 10, 7, 8, 9, 10, 7, 8, 9, 10, 7, 8, 9, 10] + [13, 13, 13, 13]) capacities = ([2, 2] + [1, 1, 1] + [1, 1, 1] + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + [1, 1, 1, 1]) costs = ([0, 0] + [0, 0, 0] + [0, 0, 0] + [90, 76, 75, 70, 35, 85, 55, 65, 125, 95, 90, 105, 45, 110, 95, 115, 60, 105, 80, 75, 45, 65, 110, 95] + [0, 0, 0, 0]) # Define an array of supplies at each node. supplies = [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4] source = 0 sink = 13 # Add each arc. for i in range(0, len(start_nodes)): min_cost_flow.AddArcWithCapacityAndUnitCost(start_nodes[i], end_nodes[i], capacities[i], costs[i]) # Add node supplies. for i in range(0, len(supplies)): min_cost_flow.SetNodeSupply(i, supplies[i]) # Find the minimum cost flow between node 0 and node 10. if min_cost_flow.Solve() == min_cost_flow.OPTIMAL: min_cost_flow.Solve() print('Total cost = ', min_cost_flow.OptimalCost()) print() for arc in range(min_cost_flow.NumArcs()): # Can ignore arcs leading out of source or intermediate nodes, or into sink. if (min_cost_flow.Tail(arc)!=0 and min_cost_flow.Tail(arc)!=11 and min_cost_flow.Tail(arc)!=12 and min_cost_flow.Head(arc)!=13): # Arcs in the solution will have a flow value of 1. There start and end nodes # give an assignment of worker to task. if min_cost_flow.Flow(arc) > 0: print('Worker %d assigned to task %d. Cost = %d' % ( min_cost_flow.Tail(arc), min_cost_flow.Head(arc), min_cost_flow.UnitCost(arc))) else: print('There was an issue with the min cost flow input.') if __name__ == '__main__': start_time = time.clock() main() print() print("Time =", time.clock() - start_time, "seconds") Total cost = 250 Worker 1 assigned to task 9. Cost = 75 Worker 2 assigned to task 7. Cost = 35 Worker 5 assigned to task 10. Cost = 75 Worker 6 assigned to task 8. Cost = 65