import java.io.*;
import java.util.*;
class Vertex {
int idNum, capacity, edgeFlow;
boolean forward; // direction;
Vertex twin; // edge in opposite direction;
Vertex() {
}
Vertex(int id, int c, int ef, boolean f) {
idNum = id; capacity = c; edgeFlow = ef; forward = f; twin = null;
}
public boolean equals(Object v) {
return idNum == ((Vertex)v).idNum;
}
public String toString() {
return (idNum + " " + capacity + " " + edgeFlow + " " + forward);
}
}
class VertexInVector {
String idName;
int vertexSlack;
boolean labeled = false;
int parent;
LinkedList adjacent = new LinkedList();
Vertex corrVer; // corresponding vertex: vertex on parent's
VertexInVector() { // list of adjacent vertices with the same
} // idNum as the cell's index;
VertexInVector(String s) {
idName = s;
}
public boolean equals(Object v) {
return idName.equals(((VertexInVector)v).idName);
}
public void display() {
System.out.print(idName + ' ' + vertexSlack + ' '
+ labeled + ' ' + parent + ' ' + corrVer + "-> ");
System.out.print(adjacent);
System.out.println();
}
}
class Network {
public Network() {
vertices.insertElementAt(new VertexInVector(), source);
vertices.insertElementAt(new VertexInVector(), sink);
((VertexInVector)vertices.elementAt(source)).idName = "source";
((VertexInVector)vertices.elementAt(sink)).idName = "sink";
((VertexInVector)vertices.elementAt(source)).parent = none;
}
protected final int sink = 1, source = 0, none = -1;
protected Vector vertices = new Vector();
protected int edgeSlack(Vertex u) {
return u.capacity - u.edgeFlow;
}
protected boolean labeled(Vertex p) {
return ((VertexInVector)vertices.elementAt(p.idNum)).labeled;
}
public void display() {
for (int i = 0; i < vertices.size(); i++) {
System.out.print(i + ": " );
((VertexInVector)vertices.elementAt(i)).display();
}
}
public void readCommittees(String fileName, InputStream fIn) {
int ch = 1, pos, commPos;
String s;
boolean lastMember;
Vertex memberVer, commVer;
VertexInVector committee, member;
try {
while (ch > -1) {
while (true)
if (ch > -1 && !Character.isLetter((char)ch)) // skip
ch = fIn.read(); // non-letters;
else break;
if (ch == -1)
break;
s = "";
while (ch > -1 && ch != ':') {
s += (char)ch;
ch = fIn.read();
}
committee = new VertexInVector(s.trim());
commPos = vertices.size();
commVer = new Vertex(commPos,1,0,false);
vertices.addElement(committee);
for (lastMember = false; !lastMember; ) {
while (true)
if (ch > -1 && !Character.isLetter((char)ch)) // skip
ch = fIn.read(); // non-letters;
else break;
if (ch == -1)
break;
s = "";
while (ch > -1 && ch != ',' && ch != ';') {
s += (char)ch;
ch = fIn.read();
}
if (ch == ';')
lastMember = true;
member = new VertexInVector(s.trim());
memberVer = new Vertex(0,1,0,true);
if ((pos = vertices.indexOf(member)) == -1) {
memberVer.idNum = vertices.size();
member.adjacent.addFirst(new Vertex(sink,1,0,true));
member.adjacent.addFirst(commVer);
vertices.addElement(member);
}
else {
memberVer.idNum = pos;
((VertexInVector)vertices.elementAt(pos)).
adjacent.addFirst(commVer);
}
committee.adjacent.addFirst(memberVer);
memberVer.twin = commVer;
commVer.twin = memberVer;
}
commVer = new Vertex(commPos,1,0,true);
((VertexInVector)vertices.elementAt(source)).adjacent.
addFirst(commVer);
}
} catch (IOException io) {
}
display();
}
private void label(Vertex u, int v) {
VertexInVector uu = (VertexInVector) vertices.elementAt(u.idNum);
VertexInVector vv = (VertexInVector) vertices.elementAt(v);
uu.labeled = true;
if (u.forward)
uu.vertexSlack = Math.min(vv.vertexSlack,edgeSlack(u));
else uu.vertexSlack = Math.min(vv.vertexSlack,u.edgeFlow);
uu.parent = v;
uu.corrVer = u;
}
private void augmentPath() {
int sinkSlack = ((VertexInVector)vertices.elementAt(sink)).vertexSlack;
Vertex u;
VertexInVector vv;
Stack path = new Stack();
for (int i = sink; i != source;
i = ((VertexInVector)vertices.elementAt(i)).parent) {
vv = (VertexInVector) vertices.elementAt(i);
path.push(vv.idName);
if (vv.corrVer.forward)
vv.corrVer.edgeFlow += sinkSlack;
else vv.corrVer.edgeFlow -= sinkSlack;
if (vv.parent != source && i != sink)
vv.corrVer.twin.edgeFlow = vv.corrVer.edgeFlow;
}
for (int i = 0; i < vertices.size(); i++)
((VertexInVector)vertices.elementAt(i)).labeled = false;
System.out.print(" source");
while (!path.isEmpty())
System.out.print(" => " + path.pop());
System.out.print(" (augmented by " + sinkSlack + ");\n");
}
public void FordFulkersonMaxFlow() {
int i, v;
Vertex u;
Iterator it;
Stack labeledS = new Stack();
for (i = 0; i < vertices.size(); i++)
((VertexInVector) vertices.elementAt(i)).labeled = false;
((VertexInVector)vertices.elementAt(source)).vertexSlack =
Integer.MAX_VALUE;
labeledS.push(new Integer(source));
System.out.println("Augmenting paths:");
while (!labeledS.isEmpty()) { // while not stuck;
v = ((Integer) labeledS.pop()).intValue();
for (it = ((VertexInVector)vertices.elementAt(v)).adjacent.iterator();
it.hasNext(); ) {
u = (Vertex) it.next();
if (!labeled(u)) {
if (u.forward && edgeSlack(u) > 0 ||
!u.forward && u.edgeFlow > 0)
label(u,v);
if (labeled(u))
if (u.idNum == sink) {
augmentPath();
labeledS.clear(); // look for another path;
labeledS.push(new Integer(source));
break;
}
else {
labeledS.push(new Integer(u.idNum));
((VertexInVector)vertices.elementAt(u.idNum)).
labeled = true;
}
}
}
}
}
}
class DistinctRepresentatives {
static public void main(String args[]) {
String fileName = "";
Network net = new Network();
InputStream fIn;
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader buffer = new BufferedReader(isr);
try {
if (args.length == 0) {
System.out.print("Enter a file name: ");
fileName = buffer.readLine();
fIn = new FileInputStream(fileName);
}
else {
fIn = new FileInputStream(args[0]);
fileName = args[0];
}
net.readCommittees(fileName,fIn);
fIn.close();
} catch(IOException io) {
System.err.println("Cannot open " + fileName);
}
net.FordFulkersonMaxFlow();
net.display();
}
}