i am a new in Cplex , so i want to know how to declare a subset included in a set .
i have a S_i : the set of flight i's Feasible start time tuples.
and i declare this et like this :
int F=...;
range flights = 1..F; // set of flights
{int} S[flights]=...; //Set of feasible start time
and i have a subset S_i (w) ⊆ S_i denote the subset of feasible start time tuples , if w working stations assigned are assigned to flight i.
i declare :
int W=...;
range workingstations=1..W;
but i couldn' t know how to declare the subset, Please help!!!
{string} flights={"A1","A2"};
{string} workingstations={"W1","W2"};
tuple tup {
int sd ; //start time of bagage handling
int sh ; // start time of storage depletion
}
{tup} ttt = {};
tuple Starttime {
int elt; //earlist_starttime
int lst; //lastest_starttime
int ed; //end time of baggage handling
tup tt;
}
tup myt1=<3,4>;
tup myt2=<4,5>;
Starttime S[flights]=[<1,2,3,myt1>,<1,2,9,myt2>];
Starttime S2[flights][workingstations]=[[<1,2,3,myt1>,<1,2,9,myt2>],[<1,2,3,myt1>,<1,2,9,myt2>]];
execute PREPROCESSING {
//initialize tup
var t1 = ttt.add(1,11);
var t2 = ttt.add(2,22);
writeln(ttt);
writeln(S);
writeln(S2);
}
//variables
dvar int+ sd ;
dvar int+ sh;
subject to
{
}
works
Related
I was busy trying to perform a sensitivity analysis in CPLEX IDE on my MILP problem. I received an error in my code as it replied that this script does not work for a MILP problem.
Would anyone know another way to do a (partly) sensitivity analysis? Or know what is wrong with my code?
This is the code I used to find the slack variables of my constraints.
Mod
int Time = ...;
int Prod = ...;
range T=0..Time;
range J=1..Prod;
// Parameters
int d [T][J] = ...; // demand in period t
int K[J] = ...; // fixed order cost in period t
int h = ...; // unit holding cost in period t
int p = ...; // fixed cost of increasing WH size in period t
int q = ...; // fixed cost of increasing WH size in period t
int e = ...; // variable cost of increasing WH size in period t
int c = ...; // variable cost of decreasing WH size in period t
int r = ...; // WH rental cost per unit in period t
dvar int+ x[T][J]; //order quantity in period t
dvar int+ i[T][J]; //inventory lvl at the end of period t
dvar int+ w[T]; // warehouse size at the end of period t
dvar int+ u[T]; // warehouse size expansion at beginning of period t
dvar int+ v[T]; // warehouse size contraction at beginning of period t
dvar boolean y[T][J]; // binary variable for ordering in period t dvar int+ y[T][J]; //// this constraint assumes that only 1 order can be placed in t
dvar boolean z1[T]; // binary variable for WH expansion in period t
dvar boolean z2[T]; // binary variable for WH contraction in period t
//objecTive funcTion
dexpr int Cost = sum(t in T,j in J)
(K[j]*y[t][j]+h*i[t][j]+p*z1[t]+e*u[t]+q*z2[t]+c*v[t]+r*w[t]);
minimize Cost;
//constraints
subject to {
forall(t in 1..Time, j in J) {
c1: i[t-1][j] + x[t][j] - d[t][j] == i[t][j]; //Inventory balance constraint
c2: w[t-1] + u[t] - v[t] == w[t]; //warehouse balance constraint
c3:sum(j in J)i[t][j] <= w[t]; // inventory should be max. the warehouse level
c4:x[t][j] <= (sum(t1 in t..Time)d[t1][j])*y[t][j]; // dtT Cumulative demand from t to end T
c5:u[t] <= (sum(t in T)d[t][j])*z1[t]; // Total demand from 1 to T * z1 u[t] <= dtot*z1[t];
c6:v[t] <= (sum(t in T)d[t][j])*z2[t]; // Total demand from 1 to T *z2 v[t] <= dtot*z2[t]; or v[t] <= (sum(t in T,j in J)d[t][j])*z2[t];
c7:w[t] <= 14000; // WH max available capacity
c8:x[t][1] <= 8000; // production capacity prod 1 in a period t
c9:x[t][2] <= 9000; // production capacity prod2 in a period t
c10:i[0][1]==100; // initial inv prod 1
c11:i[0][2]==500; // initial inv prod 2
c12:w[0]==1000; //initial warehouse size
}
}
//display solution identifier
// Post Processing Code
execute {
if(cplex.getCplexStatus()==1){
writeln("Slack variable for c1=",c1.slack);
writeln("Slack variable for c2=",c2.slack);
writeln("Slack variable for c3=",c3.slack);
writeln("Slack variable for c4=",c4.slack);
writeln("Slack variable for c5=",c5.slack);
writeln("Slack variable for c6=",c6.slack);
writeln("Slack variable for c7=",c7.slack);
writeln("Slack variable for c8=",c8.slack);
writeln("Slack variable for c9=",c9.slack);
writeln("Slack variable for c10=",c10.slack);
writeln("Slack variable for c11=",c11.slack);
writeln("Slack variable for c12=",c12.slack);
}
else {
writeln("Solution not found");
}
}
Dat
Time=4;
Prod=2;
d = [[0,0],[1500,500],[4000,2000],[200,3000],[2000,2000]];
K = [100000,200000]; // ordering costs
h = 1; // holding costs
p = 300; // fixed cost increasing size
q = 300; // fixed cost decreasing size
e = 1; // variable costs per unit increase
c = 2; // variable cost per unit decrease
r = 4; // WH rent costs
You got an error because c1 is an array of constraints and not a constraint.
If you write
//display solution identifier
range T1=1..Time;
// Post Processing Code
execute {
if(cplex.getCplexStatus()==1){
for (t in T1) for ( j in J) writeln("Slack variable for c1=",c1[t][j].slack);
}
else {
writeln("Solution not found");
}
}
instead , then you ll get a nice display
I'm a student new at CP optimizer.
I want to make battery charging/discharging scheduling in CP.
So, I want to know how to charge or discharge at each sept.
using CP;
int numEVs = ...;
range EVs = 0..numEVs-1;
int time = ...;
range times = 0..time-1;
int cost[times] = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24];
float min_soc[EVs] = [0.4,0.4,0.4,0.4,0.4];
float max_soc[EVs] = [0.9,0.9,0.9,0.9,0.9];
float Soc[EVs] = [0.4, 0.5, 0.6, 0.7, 0.8];
int k[times,EVs];
tuple EVs2 {
key int id;
int Cpower[times];
int Dpower[times];
}
//float delSm[EVs] = Soc[EVs] - min_soc[EVs];
//float delSp[EVs] = Soc[EVs] - max_soc[EVs];
dvar interval t[i in times] optional size 1;
dvar int Pcmax[times, EVs]; // why I can't use float.
dvar int Pdmax[times, EVs];
//dvar int k[times,EVs] in 0..1;
dexpr float Cost = sum(t, j in EVs) (k[t,j]*cost[t]*Pcmax[t,j] - (1-k[t,j])*cost[t]*Pdmax[t,j]);
minimize Cost; // minimize charging/discharging price
subject to {
forall(t, j in EVs)
k[t,j]*Pcmax[t,j] - (1-k[t,j])*Pdmax[t,j] >= Soc[j]-min_soc[j] && k[t,j]*Pcmax[t,j] - (1-k[t,j])*Pdmax[t,j] <= Soc[j]-max_soc[j];
// each EV's battery state of charge must less or bigger than limits.
forall(t, j in EVs)
{
Pdmax[t][j] >=0;
Pdmax[t][j] <=10;
Pcmax[t][j] >=0;
Pcmax[t][j] <=8;
}
this is my code, but not working help me plz.
Copying a short version of the answer this question got at https://www.ibm.com/developerworks/community/forums/html/topic?id=5ffa03c4-68ed-44d4-b663-998592e22dec, where it was cross posted: The model is infeasible. You can use the conflict refiner to figure out which constraints render the problem infeasible and then fix them.
Given
class Interval{
int start;
int end;
}
Task is to insert an Interval into a disjoint set or list of Intervals. So for example
<4,8> into <3,7><10,13><20,21><30,31><40,45> gives <3,8><10,13><20,21><30,31><40,45>
<1,30> into <3,7><10,13><20,21><30,31><40,45> gives <1,30><40,45>
and etc.
I know we should use 2 binary searches for the most efficient solution and that we should be comparing the inserted interval's start with the list intervals' end and vice versa. How exactly do we handle binary search when we can't find exactly what we're looking for?
Count the number of nodes. Go back to the centre, insert if applicable. Otherwise decide which half of the list is of interest. Go back to it's centre, insert etc. You need to handle the exception <4 9> into <2 5> <8 12>.
Assuming C++, I'd use an std::map from the interval end to the interval start.
For searching, use std::upper_bound() to find the first overlapping
interval and then advance the iterator to find all overlapping intervals.
Only one binary search is required.
#include <map>
#include <stdio.h>
typedef std::map<int, int> IntervalMap;
struct Interval {
int start;
int end;
};
int main()
{
IntervalMap imap;
Interval query;
imap[7] = 3; // <3,7>
imap[13] = 10; // <10,13>
// Insert: <4,8>
query.start = 4;
query.end = 8;
// Find the first overlapping interval
auto it = imap.upper_bound(query.start);
if (it != imap.end() && it->second < query.end)
{
// There is one or more overlapping interval
// Update lower bound for the new interval
if (it->second < query.start)
query.start = it->second;
while (it != imap.end() && it->second < query.end)
{
// Update upper bound for the new interval
if (it->first > query.end)
query.end = it->first;
auto tmp = it;
++it;
imap.erase(tmp);
}
}
// Insert the new interval
imap[query.end] = query.start;
for (auto it = imap.begin(); it != imap.end(); ++it)
{
fprintf(stderr, "<%d,%d>\n", it->second, it->first);
}
return 0;
}
I have recently completed the following interview exercise:
'A robot can be programmed to run "a", "b", "c"... "n" kilometers and it takes ta, tb, tc... tn minutes, respectively. Once it runs to programmed kilometers, it must be turned off for "m" minutes.
After "m" minutes it can again be programmed to run for a further "a", "b", "c"... "n" kilometers.
How would you program this robot to go an exact number of kilometers in the minimum amount of time?'
I thought it was a variation of the unbounded knapsack problem, in which the size would be the number of kilometers and the value, the time needed to complete each stretch. The main difference is that we need to minimise, rather than maximise, the value. So I used the equivalent of the following solution: http://en.wikipedia.org/wiki/Knapsack_problem#Unbounded_knapsack_problem
in which I select the minimum.
Finally, because we need an exact solution (if there is one), over the map constructed by the algorithm for all the different distances, I iterated through each and trough each robot's programmed distance to find the exact distance and minimum time among those.
I think the pause the robot takes between runs is a bit of a red herring and you just need to include it in your calculations, but it does not affect the approach taken.
I am probably wrong, because I failed the test. I don't have any other feedback as to the expected solution.
Edit: maybe I wasn't wrong after all and I failed for different reasons. I just wanted to validate my approach to this problem.
import static com.google.common.collect.Sets.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
public final class Robot {
static final Logger logger = Logger.getLogger (Robot.class);
private Set<ProgrammedRun> programmedRuns;
private int pause;
private int totalDistance;
private Robot () {
//don't expose default constructor & prevent subclassing
}
private Robot (int[] programmedDistances, int[] timesPerDistance, int pause, int totalDistance) {
this.programmedRuns = newHashSet ();
for (int i = 0; i < programmedDistances.length; i++) {
this.programmedRuns.add (new ProgrammedRun (programmedDistances [i], timesPerDistance [i] ) );
}
this.pause = pause;
this.totalDistance = totalDistance;
}
public static Robot create (int[] programmedDistances, int[] timesPerDistance, int pause, int totalDistance) {
Preconditions.checkArgument (programmedDistances.length == timesPerDistance.length);
Preconditions.checkArgument (pause >= 0);
Preconditions.checkArgument (totalDistance >= 0);
return new Robot (programmedDistances, timesPerDistance, pause, totalDistance);
}
/**
* #returns null if no strategy was found. An empty map if distance is zero. A
* map with the programmed runs as keys and number of time they need to be run
* as value.
*
*/
Map<ProgrammedRun, Integer> calculateOptimalStrategy () {
//for efficiency, consider this case first
if (this.totalDistance == 0) {
return Maps.newHashMap ();
}
//list of solutions for different distances. Element "i" of the list is the best set of runs that cover at least "i" kilometers
List <Map<ProgrammedRun, Integer>> runsForDistances = Lists.newArrayList();
//special case i = 0 -> empty map (no runs needed)
runsForDistances.add (new HashMap<ProgrammedRun, Integer> () );
for (int i = 1; i <= totalDistance; i++) {
Map<ProgrammedRun, Integer> map = new HashMap<ProgrammedRun, Integer> ();
int minimumTime = -1;
for (ProgrammedRun pr : programmedRuns) {
int distance = Math.max (0, i - pr.getDistance ());
int time = getTotalTime (runsForDistances.get (distance) ) + pause + pr.getTime();
if (minimumTime < 0 || time < minimumTime) {
minimumTime = time;
//new minimum found
map = new HashMap<ProgrammedRun, Integer> ();
map.putAll(runsForDistances.get (distance) );
//increase count
Integer num = map.get (pr);
if (num == null) num = Integer.valueOf (1);
else num++;
//update map
map.put (pr, num);
}
}
runsForDistances.add (map );
}
//last step: calculate the combination with exact distance
int minimumTime2 = -1;
int bestIndex = -1;
for (int i = 0; i <= totalDistance; i++) {
if (getTotalDistance (runsForDistances.get (i) ) == this.totalDistance ) {
int time = getTotalTime (runsForDistances.get (i) );
if (time > 0) time -= pause;
if (minimumTime2 < 0 || time < minimumTime2 ) {
minimumTime2 = time;
bestIndex = i;
}
}
}
//if solution found
if (bestIndex != -1) {
return runsForDistances.get (bestIndex);
}
//try all combinations, since none of the existing maps run for the exact distance
List <Map<ProgrammedRun, Integer>> exactRuns = Lists.newArrayList();
for (int i = 0; i <= totalDistance; i++) {
int distance = getTotalDistance (runsForDistances.get (i) );
for (ProgrammedRun pr : programmedRuns) {
//solution found
if (distance + pr.getDistance() == this.totalDistance ) {
Map<ProgrammedRun, Integer> map = new HashMap<ProgrammedRun, Integer> ();
map.putAll (runsForDistances.get (i));
//increase count
Integer num = map.get (pr);
if (num == null) num = Integer.valueOf (1);
else num++;
//update map
map.put (pr, num);
exactRuns.add (map);
}
}
}
if (exactRuns.isEmpty()) return null;
//finally return the map with the best time
minimumTime2 = -1;
Map<ProgrammedRun, Integer> bestMap = null;
for (Map<ProgrammedRun, Integer> m : exactRuns) {
int time = getTotalTime (m);
if (time > 0) time -= pause; //remove last pause
if (minimumTime2 < 0 || time < minimumTime2 ) {
minimumTime2 = time;
bestMap = m;
}
}
return bestMap;
}
private int getTotalTime (Map<ProgrammedRun, Integer> runs) {
int time = 0;
for (Map.Entry<ProgrammedRun, Integer> runEntry : runs.entrySet()) {
time += runEntry.getValue () * runEntry.getKey().getTime ();
//add pauses
time += this.pause * runEntry.getValue ();
}
return time;
}
private int getTotalDistance (Map<ProgrammedRun, Integer> runs) {
int distance = 0;
for (Map.Entry<ProgrammedRun, Integer> runEntry : runs.entrySet()) {
distance += runEntry.getValue() * runEntry.getKey().getDistance ();
}
return distance;
}
class ProgrammedRun {
private int distance;
private int time;
private transient float speed;
ProgrammedRun (int distance, int time) {
this.distance = distance;
this.time = time;
this.speed = (float) distance / time;
}
#Override public String toString () {
return "(distance =" + distance + "; time=" + time + ")";
}
#Override public boolean equals (Object other) {
return other instanceof ProgrammedRun
&& this.distance == ((ProgrammedRun)other).distance
&& this.time == ((ProgrammedRun)other).time;
}
#Override public int hashCode () {
return Objects.hashCode (Integer.valueOf (this.distance), Integer.valueOf (this.time));
}
int getDistance() {
return distance;
}
int getTime() {
return time;
}
float getSpeed() {
return speed;
}
}
}
public class Main {
/* Input variables for the robot */
private static int [] programmedDistances = {1, 2, 3, 5, 10}; //in kilometers
private static int [] timesPerDistance = {10, 5, 3, 2, 1}; //in minutes
private static int pause = 2; //in minutes
private static int totalDistance = 41; //in kilometers
/**
* #param args
*/
public static void main(String[] args) {
Robot r = Robot.create (programmedDistances, timesPerDistance, pause, totalDistance);
Map<ProgrammedRun, Integer> strategy = r.calculateOptimalStrategy ();
if (strategy == null) {
System.out.println ("No strategy that matches the conditions was found");
} else if (strategy.isEmpty ()) {
System.out.println ("No need to run; distance is zero");
} else {
System.out.println ("Strategy found:");
System.out.println (strategy);
}
}
}
Simplifying slightly, let ti be the time (including downtime) that it takes the robot to run distance di. Assume that t1/d1 ≤ … ≤ tn/dn. If t1/d1 is significantly smaller than t2/d2 and d1 and the total distance D to be run are large, then branch and bound likely outperforms dynamic programming. Branch and bound solves the integer programming formulation
minimize ∑i ti xi
subject to
∑i di xi = D
∀i xi ∈ N
by using the value of the relaxation where xi can be any nonnegative real as a guide. The latter is easily verified to be at most (t1/d1)D, by setting x1 to D/d1 and ∀i ≠ 1 xi = 0, and at least (t1/d1)D, by setting the sole variable of the dual program to t1/d1. Solving the relaxation is the bound step; every integer solution is a fractional solution, so the best integer solution requires time at least (t1/d1)D.
The branch step takes one integer program and splits it in two whose solutions, taken together, cover the entire solution space of the original. In this case, one piece could have the extra constraint x1 = 0 and the other could have the extra constraint x1 ≥ 1. It might look as though this would create subproblems with side constraints, but in fact, we can just delete the first move, or decrease D by d1 and add the constant t1 to the objective. Another option for branching is to add either the constraint xi = ⌊D/di⌋ or xi ≤ ⌊D/di⌋ - 1, which requires generalizing to upper bounds on the number of repetitions of each move.
The main loop of branch and bound selects one of a collection of subproblems, branches, computes bounds for the two subproblems, and puts them back into the collection. The efficiency over brute force comes from the fact that, when we have a solution with a particular value, every subproblem whose relaxed value is at least that much can be thrown away. Once the collection is emptied this way, we have the optimal solution.
Hybrids of branch and bound and dynamic programming are possible, for example, computing optimal solutions for small D via DP and using those values instead of branching on subproblems that have been solved.
Create array of size m and for 0 to m( m is your distance) do:
a[i] = infinite;
a[0] = 0;
a[i] = min{min{a[i-j] + tj + m for all j in possible kilometers of robot. and j≠i} , ti if i is in possible moves of robot}
a[m] is lowest possible value. Also you can have array like b to save a[i]s selection. Also if a[m] == infinite means it's not possible.
Edit: we can solve it in another way by creating a digraph, again our graph is dependent to m length of path, graph has nodes labeled {0..m}, now start from node 0 connect it to all possible nodes; means if you have a kilometer i you can connect 0 and vi with weight ti, except for node 0->x, for all other nodes you should connect node i->j with weight tj-i + m for j>i and j-i is available in input kilometers. now you should find shortest path from v0 to vn. but this algorithm still is O(nm).
Let G be the desired distance run.
Let n be the longest possible distance run without pause.
Let L = G / n (Integer arithmetic, discard fraction part)
Let R = G mod n (ie. The remainder from the above division)
Make the robot run it's longest distance (ie. n) L times, and then whichever distance (a, b, c, etc.) is greater than R by the least amount (ie the smallest available distance that is equal to or greater than R)
Either I understood the problem wrong, or you're all over thinking it
I am a big believer in showing instead of telling. Here is a program that may be doing what you are looking for. Let me know if it satisfies your question. Simply copy, paste, and run the program. You should of course test with your own data set.
import java.util.Arrays;
public class Speed {
/***
*
* #param distance
* #param sprints ={{A,Ta},{B,Tb},{C,Tc}, ..., {N,Tn}}
*/
public static int getFastestTime(int distance, int[][] sprints){
long[] minTime = new long[distance+1];//distance from 0 to distance
Arrays.fill(minTime,Integer.MAX_VALUE);
minTime[0]=0;//key=distance; value=time
for(int[] speed: sprints)
for(int d=1; d<minTime.length; d++)
if(d>=speed[0] && minTime[d] > minTime[d-speed[0]]+speed[1])
minTime[d]=minTime[d-speed[0]]+speed[1];
return (int)minTime[distance];
}//
public static void main(String... args){
//sprints ={{A,Ta},{B,Tb},{C,Tc}, ..., {N,Tn}}
int[][] sprints={{3,2},{5,3},{7,5}};
int distance = 21;
System.out.println(getFastestTime(distance,sprints));
}
}
I'd implement Edmond Karp algorithm, but seems it's not correct and I'm not getting correct flow, consider following graph and flow from 4 to 8:
Algorithm runs as follow:
First finds 4→1→8,
Then finds 4→5→8
after that 4→1→6→8
And I think third path is wrong, because by using this path we can't use flow from 6→8 (because it used), and in fact we can't use flow from 4→5→6→8.
In fact if we choose 4→5→6→8, and then 4→1→3→7→8 and then 4→1→3→7→8 we can gain better flow(40).
I Implemented algorithm from wiki sample code. I think we can't use any valid path and in fact this greedy selection is wrong.
Am I wrong?
Code is as below (in c#, threshold is 0, and doesn't affect the algorithm):
public decimal EdmondKarps(decimal[][] capacities/*Capacity matrix*/,
List<int>[] neighbors/*Neighbour lists*/,
int s /*source*/,
int t/*sink*/,
decimal threshold,
out decimal[][] flowMatrix
/*flowMatrix (A matrix giving a legal flowMatrix with the maximum value)*/
)
{
THRESHOLD = threshold;
int n = capacities.Length;
decimal flow = 0m; // (Initial flowMatrix is zero)
flowMatrix = new decimal[n][]; //array(1..n, 1..n) (Residual capacity from u to v is capacities[u,v] - flowMatrix[u,v])
for (int i = 0; i < n; i++)
{
flowMatrix[i] = new decimal[n];
}
while (true)
{
var path = new int[n];
var pathCapacity = BreadthFirstSearch(capacities, neighbors, s, t, flowMatrix, out path);
if (pathCapacity <= threshold)
break;
flow += pathCapacity;
//(Backtrack search, and update flowMatrix)
var v = t;
while (v != s)
{
var u = path[v];
flowMatrix[u][v] = flowMatrix[u][v] + pathCapacity;
flowMatrix[v][u] = flowMatrix[v][u] - pathCapacity;
v = u;
}
}
return flow;
}
private decimal BreadthFirstSearch(decimal[][] capacities, List<int>[] neighbors, int s, int t, decimal[][] flowMatrix, out int[] path)
{
var n = capacities.Length;
path = Enumerable.Range(0, n).Select(x => -1).ToArray();//array(1..n)
path[s] = -2;
var pathFlow = new decimal[n];
pathFlow[s] = Decimal.MaxValue; // INFINT
var Q = new Queue<int>(); // Q is exactly Queue :)
Q.Enqueue(s);
while (Q.Count > 0)
{
var u = Q.Dequeue();
for (int i = 0; i < neighbors[u].Count; i++)
{
var v = neighbors[u][i];
//(If there is available capacity, and v is not seen before in search)
if (capacities[u][v] - flowMatrix[u][v] > THRESHOLD && path[v] == -1)
{
// save path:
path[v] = u;
pathFlow[v] = Math.Min(pathFlow[u], capacities[u][v] - flowMatrix[u][v]);
if (v != t)
Q.Enqueue(v);
else
return pathFlow[t];
}
}
}
return 0;
}
The way to choose paths is not important.
You have to add edges of the path in reverse order with path capacity and reduce capacity of edges of the path by that value.
In fact this solution works:
while there is a path with positive capacity from source to sink{
find any path with positive capacity from source to sink, named P with capacity C.
add C to maximum_flow_value.
reduce C from capacity of edges of P.
add C to capacity of edges of reverse_P.
}
Finally the value of maximum-flow is sum of Cs in the loop.
If you want to see the flow in edges in the maximum-flow you made, you can retain the initial graph somewhere, the flow in edge e would be original_capacity_e - current_capacity_e.