FlowEdge.java
8.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
/******************************************************************************
* Compilation: javac FlowEdge.java
* Execution: java FlowEdge
* Dependencies: StdOut.java
*
* Capacitated edge with a flow in a flow network.
*
******************************************************************************/
package edu.princeton.cs.algs4;
/**
* The {@code FlowEdge} class represents a capacitated edge with a
* flow in a {@link FlowNetwork}. Each edge consists of two integers
* (naming the two vertices), a real-valued capacity, and a real-valued
* flow. The data type provides methods for accessing the two endpoints
* of the directed edge and the weight. It also provides methods for
* changing the amount of flow on the edge and determining the residual
* capacity of the edge.
* <p>
* For additional documentation, see <a href="http://algs4.cs.princeton.edu/64maxflow">Section 6.4</a> of
* <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne.
*
* @author Robert Sedgewick
* @author Kevin Wayne
*/
public class FlowEdge {
// to deal with floating-point roundoff errors
private static final double FLOATING_POINT_EPSILON = 1E-10;
private final int v; // from
private final int w; // to
private final double capacity; // capacity
private double flow; // flow
/**
* Initializes an edge from vertex {@code v} to vertex {@code w} with
* the given {@code capacity} and zero flow.
* @param v the tail vertex
* @param w the head vertex
* @param capacity the capacity of the edge
* @throws IllegalArgumentException if either {@code v} or {@code w}
* is a negative integer
* @throws IllegalArgumentException if {@code capacity < 0.0}
*/
public FlowEdge(int v, int w, double capacity) {
if (v < 0) throw new IllegalArgumentException("vertex index must be a non-negative integer");
if (w < 0) throw new IllegalArgumentException("vertex index must be a non-negative integer");
if (!(capacity >= 0.0)) throw new IllegalArgumentException("Edge capacity must be non-negative");
this.v = v;
this.w = w;
this.capacity = capacity;
this.flow = 0.0;
}
/**
* Initializes an edge from vertex {@code v} to vertex {@code w} with
* the given {@code capacity} and {@code flow}.
* @param v the tail vertex
* @param w the head vertex
* @param capacity the capacity of the edge
* @param flow the flow on the edge
* @throws IllegalArgumentException if either {@code v} or {@code w}
* is a negative integer
* @throws IllegalArgumentException if {@code capacity} is negative
* @throws IllegalArgumentException unless {@code flow} is between
* {@code 0.0} and {@code capacity}.
*/
public FlowEdge(int v, int w, double capacity, double flow) {
if (v < 0) throw new IllegalArgumentException("vertex index must be a non-negative integer");
if (w < 0) throw new IllegalArgumentException("vertex index must be a non-negative integer");
if (!(capacity >= 0.0)) throw new IllegalArgumentException("edge capacity must be non-negative");
if (!(flow <= capacity)) throw new IllegalArgumentException("flow exceeds capacity");
if (!(flow >= 0.0)) throw new IllegalArgumentException("flow must be non-negative");
this.v = v;
this.w = w;
this.capacity = capacity;
this.flow = flow;
}
/**
* Initializes a flow edge from another flow edge.
* @param e the edge to copy
*/
public FlowEdge(FlowEdge e) {
this.v = e.v;
this.w = e.w;
this.capacity = e.capacity;
this.flow = e.flow;
}
/**
* Returns the tail vertex of the edge.
* @return the tail vertex of the edge
*/
public int from() {
return v;
}
/**
* Returns the head vertex of the edge.
* @return the head vertex of the edge
*/
public int to() {
return w;
}
/**
* Returns the capacity of the edge.
* @return the capacity of the edge
*/
public double capacity() {
return capacity;
}
/**
* Returns the flow on the edge.
* @return the flow on the edge
*/
public double flow() {
return flow;
}
/**
* Returns the endpoint of the edge that is different from the given vertex
* (unless the edge represents a self-loop in which case it returns the same vertex).
* @param vertex one endpoint of the edge
* @return the endpoint of the edge that is different from the given vertex
* (unless the edge represents a self-loop in which case it returns the same vertex)
* @throws IllegalArgumentException if {@code vertex} is not one of the endpoints
* of the edge
*/
public int other(int vertex) {
if (vertex == v) return w;
else if (vertex == w) return v;
else throw new IllegalArgumentException("invalid endpoint");
}
/**
* Returns the residual capacity of the edge in the direction
* to the given {@code vertex}.
* @param vertex one endpoint of the edge
* @return the residual capacity of the edge in the direction to the given vertex
* If {@code vertex} is the tail vertex, the residual capacity equals
* {@code capacity() - flow()}; if {@code vertex} is the head vertex, the
* residual capacity equals {@code flow()}.
* @throws IllegalArgumentException if {@code vertex} is not one of the endpoints of the edge
*/
public double residualCapacityTo(int vertex) {
if (vertex == v) return flow; // backward edge
else if (vertex == w) return capacity - flow; // forward edge
else throw new IllegalArgumentException("invalid endpoint");
}
/**
* Increases the flow on the edge in the direction to the given vertex.
* If {@code vertex} is the tail vertex, this increases the flow on the edge by {@code delta};
* if {@code vertex} is the head vertex, this decreases the flow on the edge by {@code delta}.
* @param vertex one endpoint of the edge
* @param delta amount by which to increase flow
* @throws IllegalArgumentException if {@code vertex} is not one of the endpoints
* of the edge
* @throws IllegalArgumentException if {@code delta} makes the flow on
* on the edge either negative or larger than its capacity
* @throws IllegalArgumentException if {@code delta} is {@code NaN}
*/
public void addResidualFlowTo(int vertex, double delta) {
if (!(delta >= 0.0)) throw new IllegalArgumentException("Delta must be nonnegative");
if (vertex == v) flow -= delta; // backward edge
else if (vertex == w) flow += delta; // forward edge
else throw new IllegalArgumentException("invalid endpoint");
// round flow to 0 or capacity if within floating-point precision
if (Math.abs(flow) <= FLOATING_POINT_EPSILON)
flow = 0;
if (Math.abs(flow - capacity) <= FLOATING_POINT_EPSILON)
flow = capacity;
if (!(flow >= 0.0)) throw new IllegalArgumentException("Flow is negative");
if (!(flow <= capacity)) throw new IllegalArgumentException("Flow exceeds capacity");
}
/**
* Returns a string representation of the edge.
* @return a string representation of the edge
*/
public String toString() {
return v + "->" + w + " " + flow + "/" + capacity;
}
/**
* Unit tests the {@code FlowEdge} data type.
*
* @param args the command-line arguments
*/
public static void main(String[] args) {
FlowEdge e = new FlowEdge(12, 23, 4.56);
StdOut.println(e);
}
}
/******************************************************************************
* Copyright 2002-2016, Robert Sedgewick and Kevin Wayne.
*
* This file is part of algs4.jar, which accompanies the textbook
*
* Algorithms, 4th edition by Robert Sedgewick and Kevin Wayne,
* Addison-Wesley Professional, 2011, ISBN 0-321-57351-X.
* http://algs4.cs.princeton.edu
*
*
* algs4.jar is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* algs4.jar is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with algs4.jar. If not, see http://www.gnu.org/licenses.
******************************************************************************/