Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_mincost.H
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
70#ifndef TPL_MINCOST_H
71#define TPL_MINCOST_H
72
73#include <limits>
74#include <queue>
75#include <functional>
76#include <tpl_netcost.H>
77#include <tpl_dynBinHeap.H>
78#include <ah-errors.H>
79
80namespace Aleph
81{
82
83//==============================================================================
84// SUCCESSIVE SHORTEST PATHS (SSP) ALGORITHM
85//==============================================================================
86
93template <typename Flow_Type>
95{
98 bool in_tree{false};
99 void* parent_arc{nullptr};
100 void* parent_node{nullptr};
101 bool forward{true};
102
103 void reset()
104 {
105 distance = std::numeric_limits<Flow_Type>::max();
106 in_tree = false;
107 parent_arc = nullptr;
108 parent_node = nullptr;
109 }
110};
111
115template <class Net>
117ssp_info(typename Net::Node* p) noexcept
118{
119 return *static_cast<SSP_Node_Info<typename Net::Flow_Type>*>(NODE_COOKIE(p));
120}
121
132template <class Net>
133typename Net::Flow_Type reduced_cost(const Net& net, typename Net::Arc* arc,
134 typename Net::Node* from, bool forward)
135{
136 (void)from;
137 using Flow_Type = typename Net::Flow_Type;
138
139 auto src = net.get_src_node(arc);
140 auto tgt = net.get_tgt_node(arc);
141
142 Flow_Type pi_src = ssp_info<Net>(src).potential;
143 Flow_Type pi_tgt = ssp_info<Net>(tgt).potential;
144
145 // Forward arc: src -> tgt with cost arc->cost
146 // Reduced cost = cost + π(src) - π(tgt)
147 if (forward)
148 return arc->cost + pi_src - pi_tgt;
149
150 // Backward arc: tgt -> src with cost -arc->cost
151 // Reduced cost = -cost + π(tgt) - π(src)
152 return -arc->cost + pi_tgt - pi_src;
153}
154
162template <class Net>
163bool ssp_shortest_path(Net& net, typename Net::Node* source,
164 typename Net::Node* sink)
165{
166 using Node = typename Net::Node;
167 using Arc = typename Net::Arc;
168 using Flow_Type = typename Net::Flow_Type;
169
170 const Flow_Type INF = std::numeric_limits<Flow_Type>::max();
171
172 // Reset distances
173 for (Node_Iterator<Net> it(net); it.has_curr(); it.next_ne())
174 ssp_info<Net>(it.get_curr()).reset();
175
176 ssp_info<Net>(source).distance = 0;
177
178 // Priority queue: (distance, node)
179 using PQ_Entry = std::pair<Flow_Type, Node*>;
180 std::priority_queue<PQ_Entry, std::vector<PQ_Entry>, std::greater<PQ_Entry>> pq;
181
182 pq.push({0, source});
183
184 while (not pq.empty())
185 {
186 auto [dist, u] = pq.top();
187 pq.pop();
188
189 if (dist > ssp_info<Net>(u).distance)
190 continue; // Outdated entry
191
192 // Explore all adjacent arcs
193 for (typename Net::Node_Arc_Iterator it(u); it.has_curr(); it.next_ne())
194 {
195 Arc* arc = it.get_curr();
196 Node* v = net.get_connected_node(arc, u);
197
198 // Determine direction and residual capacity
199 bool forward = (net.get_src_node(arc) == u);
200 Flow_Type residual = forward ? (arc->cap - arc->flow) : arc->flow;
201
202 if (residual <= Flow_Type{0})
203 continue;
204
205 // Compute reduced cost
206 Flow_Type rc = reduced_cost<Net>(net, arc, u, forward);
207
208 // Relaxation
209 Flow_Type new_dist = ssp_info<Net>(u).distance + rc;
210 if (new_dist < ssp_info<Net>(v).distance)
211 {
212 ssp_info<Net>(v).distance = new_dist;
213 ssp_info<Net>(v).parent_arc = arc;
214 ssp_info<Net>(v).parent_node = u;
215 ssp_info<Net>(v).forward = forward;
216 pq.push({new_dist, v});
217 }
218 }
219 }
220
221 return ssp_info<Net>(sink).distance < INF;
222}
223
261template <class Net>
262std::pair<typename Net::Flow_Type, typename Net::Flow_Type>
264
276template <class Net>
277bool ssp_init_potentials(Net& net, typename Net::Node* source)
278{
279 using Flow_Type = typename Net::Flow_Type;
280
281 const Flow_Type INF = std::numeric_limits<Flow_Type>::max();
282 const size_t n = net.vsize();
283
284 // Initialize distances
285 for (Node_Iterator<Net> it(net); it.has_curr(); it.next_ne())
286 ssp_info<Net>(it.get_curr()).potential = INF;
287 ssp_info<Net>(source).potential = 0;
288
289 // Bellman-Ford: relax all edges n-1 times
290 for (size_t i = 0; i < n - 1; ++i)
291 {
292 bool changed = false;
293 for (Arc_Iterator<Net> it(net); it.has_curr(); it.next_ne())
294 {
295 auto arc = it.get_curr();
296 auto src = net.get_src_node(arc);
297 auto tgt = net.get_tgt_node(arc);
298
299 // Forward arc (if has residual capacity)
300 if (arc->cap > arc->flow)
301 {
302 Flow_Type d = ssp_info<Net>(src).potential;
303 if (d < INF)
304 {
305 Flow_Type new_d = d + arc->cost;
306 if (new_d < ssp_info<Net>(tgt).potential)
307 {
308 ssp_info<Net>(tgt).potential = new_d;
309 changed = true;
310 }
311 }
312 }
313
314 // Backward arc (if has flow to cancel)
315 if (arc->flow > 0)
316 {
317 Flow_Type d = ssp_info<Net>(tgt).potential;
318 if (d < INF)
319 {
320 Flow_Type new_d = d - arc->cost; // negative cost for backward
321 if (new_d < ssp_info<Net>(src).potential)
322 {
323 ssp_info<Net>(src).potential = new_d;
324 changed = true;
325 }
326 }
327 }
328 }
329 if (!changed) break;
330 }
331
332 // Set unreachable nodes to 0 (they won't affect anything)
333 for (Node_Iterator<Net> it(net); it.has_curr(); it.next_ne())
334 if (ssp_info<Net>(it.get_curr()).potential >= INF)
335 ssp_info<Net>(it.get_curr()).potential = 0;
336
337 return true; // No negative cycle check for simplicity
338}
339
340template <class Net>
341std::pair<typename Net::Flow_Type, typename Net::Flow_Type>
343{
344 using Node = typename Net::Node;
345 using Arc = typename Net::Arc;
346 using Flow_Type = typename Net::Flow_Type;
347
349 << "Network must have single source and single sink";
350
351 Node* source = net.get_source();
352 Node* sink = net.get_sink();
353
354 // Allocate node info using std::vector to allow taking address of elements
355 std::vector<SSP_Node_Info<Flow_Type>> node_info(net.vsize());
356 size_t idx = 0;
357 for (Node_Iterator<Net> it(net); it.has_curr(); it.next_ne(), ++idx)
358 NODE_COOKIE(it.get_curr()) = &node_info[idx];
359
360 // Initialize potentials using Bellman-Ford to handle possible negative costs
361 ssp_init_potentials(net, source);
362
363 Flow_Type total_flow{0};
364 Flow_Type total_cost{0};
365
366 // Main loop: find shortest augmenting paths
367 while (ssp_shortest_path(net, source, sink))
368 {
369 // Find minimum residual capacity on path
370 Flow_Type path_flow = std::numeric_limits<Flow_Type>::max();
371 for (Node* v = sink; v != source;)
372 {
373 Arc* arc = static_cast<Arc*>(ssp_info<Net>(v).parent_arc);
374 bool forward = ssp_info<Net>(v).forward;
375
376 Flow_Type residual = forward ? (arc->cap - arc->flow) : arc->flow;
377 path_flow = std::min(path_flow, residual);
378
379 v = static_cast<Node*>(ssp_info<Net>(v).parent_node);
380 }
381
382 // Augment flow and compute cost
383 for (Node* v = sink; v != source;)
384 {
385 Arc* arc = static_cast<Arc*>(ssp_info<Net>(v).parent_arc);
386 bool forward = ssp_info<Net>(v).forward;
387
388 if (forward)
389 {
390 arc->flow += path_flow;
391 total_cost += path_flow * arc->cost;
392 }
393 else
394 {
395 arc->flow -= path_flow;
396 total_cost -= path_flow * arc->cost;
397 }
398
399 v = static_cast<Node*>(ssp_info<Net>(v).parent_node);
400 }
401
402 total_flow += path_flow;
403
404 // Update potentials for reachable nodes
405 Flow_Type max_potential = std::numeric_limits<Flow_Type>::lowest();
406 for (Node_Iterator<Net> it(net); it.has_curr(); it.next_ne())
407 {
408 auto p = it.get_curr();
409 if (ssp_info<Net>(p).distance < std::numeric_limits<Flow_Type>::max())
410 {
411 ssp_info<Net>(p).potential += ssp_info<Net>(p).distance;
412 max_potential = std::max(max_potential, ssp_info<Net>(p).potential);
413 }
414 }
415
416 // For unreachable nodes, set potential to max to avoid negative reduced costs
417 // when backward arcs to them become available
418 for (Node_Iterator<Net> it(net); it.has_curr(); it.next_ne())
419 {
420 auto p = it.get_curr();
421 if (ssp_info<Net>(p).distance >= std::numeric_limits<Flow_Type>::max())
422 ssp_info<Net>(p).potential = max_potential;
423 }
424 }
425
426 return {total_flow, total_cost};
427}
428
432template <class Net>
434{
435 std::pair<typename Net::Flow_Type, typename Net::Flow_Type>
436 operator()(Net& net) const
437 {
438 return successive_shortest_paths(net);
439 }
440};
441
442
443//==============================================================================
444// MINIMUM COST FLOW WITH DEMAND (TRANSSHIPMENT)
445//==============================================================================
446
455template <typename Flow_Type>
460
464template <typename Flow_Type>
471
506template <class Net, class GetDemand>
509{
510 using Node = typename Net::Node;
511 using Flow_Type = typename Net::Flow_Type;
512
514
515 // Calculate total supply and demand
516 Flow_Type total_supply{0};
517 Flow_Type total_demand{0};
518
519 for (Node_Iterator<Net> it(net); it.has_curr(); it.next_ne())
520 {
521 Flow_Type d = get_demand(it.get_curr());
522 if (d > 0)
523 total_supply += d;
524 else
525 total_demand -= d;
526 }
527
528 // Check balance
529 if (total_supply != total_demand)
530 {
531 result.feasible = false;
532 return result;
533 }
534
535 // Create super-source and super-sink
536 Node* super_source = net.insert_node();
537 Node* super_sink = net.insert_node();
538
539 // Connect super-source to supply nodes
540 for (Node_Iterator<Net> it(net); it.has_curr(); it.next_ne())
541 {
542 Node* p = it.get_curr();
543 if (p == super_source or p == super_sink)
544 continue;
545
546 Flow_Type d = get_demand(p);
547 if (d > 0)
548 net.insert_arc(super_source, p, d, Flow_Type{0}); // zero cost
549 else if (d < 0)
550 net.insert_arc(p, super_sink, -d, Flow_Type{0}); // zero cost
551 }
552
553 // Source and sink are detected automatically by network topology
554
555 // Solve min-cost max-flow
556 auto [flow, cost] = successive_shortest_paths(net);
557
558 result.total_flow = flow;
559 result.total_cost = cost;
560 result.feasible = (flow == total_supply);
561
562 // Clean up (remove super nodes)
563 // Note: In real implementation, would need to properly remove these
564
565 return result;
566}
567
568
569//==============================================================================
570// ASSIGNMENT PROBLEM
571//==============================================================================
572
576template <typename Cost_Type>
583
616template <typename Cost_Type>
618solve_assignment(const std::vector<std::vector<Cost_Type>>& costs)
619{
622 using Node = typename Net::Node;
623
625
626 size_t n = costs.size();
627 if (n == 0)
628 {
629 result.feasible = true;
630 return result;
631 }
632
633 // Verify square matrix
634 for (const auto& row : costs)
635 if (row.size() != n)
636 {
637 result.feasible = false;
638 return result;
639 }
640
641 Net net;
642
643 // Create source and sink
644 Node* source = net.insert_node();
645 Node* sink = net.insert_node();
646
647 // Create worker nodes
648 std::vector<Node*> workers(n);
649 for (size_t i = 0; i < n; ++i)
650 {
651 workers[i] = net.insert_node();
652 net.insert_arc(source, workers[i], Cost_Type{1}, Cost_Type{0});
653 }
654
655 // Create task nodes
656 std::vector<Node*> tasks(n);
657 for (size_t j = 0; j < n; ++j)
658 {
659 tasks[j] = net.insert_node();
660 net.insert_arc(tasks[j], sink, Cost_Type{1}, Cost_Type{0});
661 }
662
663 // Create worker-task arcs with costs
664 for (size_t i = 0; i < n; ++i)
665 for (size_t j = 0; j < n; ++j)
666 net.insert_arc(workers[i], tasks[j], Cost_Type{1}, costs[i][j]);
667
668 // Source and sink are detected automatically by network topology
669
670 // Solve
671 auto [flow, cost] = successive_shortest_paths(net);
672
673 result.feasible = (static_cast<size_t>(flow) == n);
674 result.total_cost = cost;
675
676 // Extract assignments from flow
677 if (result.feasible)
678 {
679 for (size_t i = 0; i < n; ++i)
680 {
681 for (typename Net::Node_Arc_Iterator it(workers[i]); it.has_curr();
682 it.next_ne())
683 {
684 auto arc = it.get_curr();
685 auto tgt = net.get_tgt_node(arc);
686
687 // Find which task this is
688 for (size_t j = 0; j < n; ++j)
689 if (tasks[j] == tgt and arc->flow > 0)
690 {
691 result.assignments.append(std::make_pair(i, j));
692 break;
693 }
694 }
695 }
696 }
697
698 return result;
699}
700
701
702//==============================================================================
703// TRANSPORTATION PROBLEM
704//==============================================================================
705
709template <typename Cost_Type>
711{
712 bool feasible{false};
714 std::vector<std::vector<Cost_Type>> shipments;
715};
716
748template <typename Cost_Type>
750solve_transportation(const std::vector<Cost_Type>& supplies,
751 const std::vector<Cost_Type>& demands,
752 const std::vector<std::vector<Cost_Type>>& costs)
753{
756 using Node = typename Net::Node;
757 using Arc = typename Net::Arc;
758
760
761 size_t m = supplies.size(); // sources
762 size_t n = demands.size(); // destinations
763
764 if (m == 0 or n == 0)
765 {
766 result.feasible = true;
767 return result;
768 }
769
770 // Check supply-demand balance
771 Cost_Type total_supply = Cost_Type{0};
772 Cost_Type total_demand = Cost_Type{0};
773 for (auto s : supplies) total_supply += s;
774 for (auto d : demands) total_demand += d;
775
776 if (total_supply != total_demand)
777 {
778 result.feasible = false;
779 return result;
780 }
781
782 Net net;
783
784 // Create source and sink
785 Node* source = net.insert_node();
786 Node* sink = net.insert_node();
787
788 // Create supply nodes
789 std::vector<Node*> supply_nodes(m);
790 for (size_t i = 0; i < m; ++i)
791 {
792 supply_nodes[i] = net.insert_node();
793 net.insert_arc(source, supply_nodes[i], supplies[i], Cost_Type{0});
794 }
795
796 // Create demand nodes
797 std::vector<Node*> demand_nodes(n);
798 for (size_t j = 0; j < n; ++j)
799 {
800 demand_nodes[j] = net.insert_node();
801 net.insert_arc(demand_nodes[j], sink, demands[j], Cost_Type{0});
802 }
803
804 // Create arcs between supplies and demands
805 // Store arcs for extracting solution
806 std::vector<std::vector<Arc*>> arcs(m, std::vector<Arc*>(n));
807 for (size_t i = 0; i < m; ++i)
808 for (size_t j = 0; j < n; ++j)
809 arcs[i][j] = net.insert_arc(supply_nodes[i], demand_nodes[j],
810 std::min(supplies[i], demands[j]) + Cost_Type{1},
811 costs[i][j]);
812
813 // Source and sink are detected automatically by network topology
814
815 // Solve
816 auto [flow, cost] = successive_shortest_paths(net);
817
818 result.feasible = (flow == total_supply);
819 result.total_cost = cost;
820
821 // Extract shipments
822 result.shipments.resize(m, std::vector<Cost_Type>(n, Cost_Type{0}));
823 for (size_t i = 0; i < m; ++i)
824 for (size_t j = 0; j < n; ++j)
825 result.shipments[i][j] = arcs[i][j]->flow;
826
827 return result;
828}
829
830
831//==============================================================================
832// MIN-COST FLOW STATISTICS
833//==============================================================================
834
838template <typename Flow_Type>
840{
843 size_t iterations{0};
844 size_t augmentations{0};
845 double elapsed_ms{0};
846
847 void print() const
848 {
849 std::cout << "=== Min-Cost Flow Statistics ===\n"
850 << "Max flow: " << max_flow << "\n"
851 << "Min cost: " << min_cost << "\n"
852 << "Iterations: " << iterations << "\n"
853 << "Augmentations: " << augmentations << "\n"
854 << "Time: " << elapsed_ms << " ms\n";
855 }
856};
857
858
859//==============================================================================
860// WARM START FOR NETWORK SIMPLEX
861//==============================================================================
862
874template <class Net>
877{
879
880 for (Arc_Iterator<Net> it(net); it.has_curr(); it.next_ne())
881 {
882 auto arc = it.get_curr();
883 solution[arc] = arc->flow;
884 }
885
886 return solution;
887}
888
900template <class Net>
903{
904 for (Arc_Iterator<Net> it(net); it.has_curr(); it.next_ne())
905 {
906 auto arc = it.get_curr();
907 if (solution.has(arc))
908 arc->flow = solution[arc];
909 }
910}
911
912} // namespace Aleph
913
914#endif // TPL_MINCOST_H
Exception handling system with formatted messages for Aleph-w.
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:522
WeightedDigraph::Node Node
WeightedDigraph::Arc Arc
bool has_curr() const noexcept
Check if there is a current valid item.
Definition array_it.H:219
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
T & top() const
Definition htlist.H:1683
T & append(const T &item)
Append a new item by copy.
Definition htlist.H:1562
T & push(const T &item)
Definition htlist.H:1523
void empty() noexcept
empty the list
Definition htlist.H:1689
Generic key-value map implemented on top of a binary search tree.
bool has(const Key &key) const noexcept
void next_ne() noexcept
Advances the iterator to the next filtered element (noexcept version).
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
void reset() noexcept
Definition htlist.H:516
Filtered iterator on the nodes of a graph.
Definition tpl_graph.H:1206
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Definition graph-dry.H:731
Node * get_connected_node(Arc *arc, Node *node) const noexcept
Return the adjacent node to node through arc.
Definition graph-dry.H:772
constexpr size_t vsize() const noexcept
Definition graph-dry.H:698
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:737
DynArray< Graph::Arc * > arcs
Definition graphpic.C:408
#define NODE_COOKIE(p)
Return the node cookie
double Flow_Type
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
Net::Flow_Type reduced_cost(const Net &net, typename Net::Arc *arc, typename Net::Node *from, bool forward)
Compute reduced cost of an arc.
bool ssp_init_potentials(Net &net, typename Net::Node *source)
Initialize potentials using Bellman-Ford.
void restore_flow_solution(Net &net, const DynMapTree< typename Net::Arc *, typename Net::Flow_Type > &solution)
Restore network simplex solution from warm start.
TransportationResult< Cost_Type > solve_transportation(const std::vector< Cost_Type > &supplies, const std::vector< Cost_Type > &demands, const std::vector< std::vector< Cost_Type > > &costs)
Solve the transportation problem using min-cost flow.
SSP_Node_Info< typename Net::Flow_Type > & ssp_info(typename Net::Node *p) noexcept
Access SSP node info.
TransshipmentResult< typename Net::Flow_Type > solve_transshipment(Net &net, GetDemand get_demand)
Solve minimum cost transshipment problem.
std::pair< typename Net::Flow_Type, typename Net::Flow_Type > successive_shortest_paths(Net &net)
Compute minimum cost maximum flow using Successive Shortest Paths.
AssignmentResult< Cost_Type > solve_assignment(const std::vector< std::vector< Cost_Type > > &costs)
Solve the assignment problem using min-cost flow.
bool ssp_shortest_path(Net &net, typename Net::Node *source, typename Net::Node *sink)
Find shortest path using Dijkstra with potentials.
DynMapTree< typename Net::Arc *, typename Net::Flow_Type > save_flow_solution(const Net &net)
Save network simplex solution for warm start.
DynList< T > maps(const C &c, Op op)
Classic map operation.
Filtered iterator on all the arcs of a graph.
Definition tpl_graph.H:1164
Result of assignment problem.
DynList< std::pair< size_t, size_t > > assignments
(worker, task) pairs
Statistics for min-cost flow algorithms.
Arc type for maximum flow minimum cost networks.
Definition tpl_netcost.H:93
Capacitated flow network with costs associated to arcs.
Flow network implemented with adjacency lists.
Definition tpl_net.H:261
Node * insert_node(const Node_Type &node_info)
Insert a new node by copying node_info.
Definition tpl_net.H:559
constexpr bool is_single_source() const noexcept
Return true if the network has a single source.
Definition tpl_net.H:369
Node * get_source() const
Return an arbitrary source node.
Definition tpl_net.H:548
Arc * insert_arc(Node *src_node, Node *tgt_node, const Flow_Type &cap, const Flow_Type &flow, const typename Arc::Arc_Type &arc_info=Arc_Type())
Insert a capacitated arc with an initial flow.
Definition tpl_net.H:607
ArcT Arc
Arc type.
Definition tpl_net.H:272
Node * get_sink() const
Return an arbitrary sink node.
Definition tpl_net.H:551
typename Arc::Flow_Type Flow_Type
Capacity/flow numeric type.
Definition tpl_net.H:278
constexpr bool is_single_sink() const noexcept
Return true if the network has a single sink.
Definition tpl_net.H:372
NodeT Node
Node type.
Definition tpl_net.H:275
Node info for SSP algorithm.
Definition tpl_mincost.H:95
bool forward
Direction of parent arc.
Flow_Type distance
Shortest path distance.
Definition tpl_mincost.H:97
bool in_tree
Is node in shortest path tree?
Definition tpl_mincost.H:98
Flow_Type potential
Node potential for reduced costs.
Definition tpl_mincost.H:96
void * parent_node
Parent node.
void * parent_arc
Parent arc in shortest path tree.
Definition tpl_mincost.H:99
Functor wrapper for SSP algorithm.
std::pair< typename Net::Flow_Type, typename Net::Flow_Type > operator()(Net &net) const
Result of transportation problem.
std::vector< std::vector< Cost_Type > > shipments
shipments[i][j] from i to j
Result of transshipment problem.
Flow_Type total_cost
Total transportation cost.
bool feasible
Is there a feasible solution?
Flow_Type total_flow
Total flow shipped.
Node with supply/demand for transshipment problems.
Flow_Type demand
Positive = supply, negative = demand.
Dynamic binary heap with node-based storage.
Maximum flow minimum cost network algorithms.