#include #include #include #include #include #include #include #include using namespace std; class Node { public: string name; list adj; int visited; }; class Edge { public: string name; Node *n1; Node *n2; Edge *reverse; int original; int residual; int flow; list ::iterator iterator; }; class Graph { public: Graph(); ~Graph(); void Print(); Node *Get_Node(string &s); Edge *Get_Edge(Node *n1, Node *n2); int Find_Max_Flow(); int Find_Augmenting_Path(); int DFS(Node *n); int Print_Paths; vector Path; Node *Source; Node *Sink; vector Nodes; vector Edges; map N_Map; map E_Map; }; int Graph::Find_Max_Flow() { int total; int f; Edge *e; Node *n; int i; list ::iterator eit; for (i = 0; i < Edges.size(); i++) { e = Edges[i]; e->flow = 0; e->residual = e->original; } total = 0; while (1) { f = Find_Augmenting_Path(); if (f == 0) { return total; } else { total += f; } } } int Graph::Find_Augmenting_Path() { int i; int f; Edge *e; for (i = 0; i < Nodes.size(); i++) Nodes[i]->visited = 0; Path.clear(); if (DFS(Source)) { f = Path[0]->residual; for (i = 1; i < Path.size(); i++) { if (Path[i]->residual < f) f = Path[i]->residual; } for (i = 0; i < Path.size(); i++) { e = Path[i]; e->residual -= f; e->flow += f; if (e->residual == 0) e->n1->adj.erase(e->iterator); e->reverse->residual += f; if (e->reverse->residual == f) { e->n2->adj.push_front(e->reverse); e->reverse->iterator = e->n2->adj.begin(); } } if (Print_Paths) { printf("Found path with flow of %d:", f); for (i = Path.size()-1; i >= 0; i--) printf(" %s", Path[i]->name.c_str()); printf("\n"); } return f; } else { return 0; } } int Graph::DFS(Node *n) { Edge *e; int f; list ::iterator eit; if (n->visited) return 0; n->visited = 1; if (n == Sink) return 1; for (eit = n->adj.begin(); eit != n->adj.end(); eit++) { e = *eit; if (DFS(e->n2)) { Path.push_back(e); return 1; } } return 0; } void Graph::Print() { Node *n; Edge *e; list ::iterator eit; int i; printf("Source: %s\n", Source->name.c_str()); printf("Sink: %s\n", Sink->name.c_str()); for (i = 0; i < Nodes.size(); i++) { n = Nodes[i]; printf("Node %s:", n->name.c_str()); for (eit = n->adj.begin(); eit != n->adj.end(); eit++) { e = *eit; printf(" (%s:%d)", e->name.c_str(), e->original); } printf("\n"); } } Graph::Graph() { string s, f, t; int cap; Node *n1, *n2; Edge *e; int i; Source = NULL; Sink = NULL; while (cin >> s) { if (s == "SOURCE") { cin >> s; if (Source != NULL) { fprintf(stderr, "Can't specify two sources\n"); exit(1); } Source = Get_Node(s); } else if (s == "SINK") { cin >> s; if (Sink != NULL) { fprintf(stderr, "Can't specify two sinks\n"); exit(1); } Sink = Get_Node(s); } else if (s == "EDGE") { cin >> f >> t >> cap; n1 = Get_Node(f); n2 = Get_Node(t); e = Get_Edge(n1, n2); e->original += cap; if (e->reverse == NULL) { e->reverse = Get_Edge(n2, n1); e->reverse->reverse = e; } } } if (Source == NULL) { fprintf(stderr, "No Source.\n"); exit(1); } if (Sink == NULL) { fprintf(stderr, "No Sink.\n"); exit(1); } for (i = 0; i < Edges.size(); i++) { e = Edges[i]; if (e->original > 0) { e->n1->adj.push_front(e); e->iterator = e->n1->adj.begin(); } } } Graph::~Graph() { int i; for (i = 0; i < Nodes.size(); i++) delete(Nodes[i]); for (i = 0; i < Edges.size(); i++) delete(Edges[i]); } Node *Graph::Get_Node(string &s) { map ::iterator nit; Node *n; nit = N_Map.find(s); if (nit != N_Map.end()) return nit->second; n = new Node; n->name = s; Nodes.push_back(n); N_Map.insert(make_pair(s, n)); return n; } Edge *Graph::Get_Edge(Node *n1, Node *n2) { map ::iterator eit; Edge *e; string name; name = n1->name + "->"; name += n2->name; eit = E_Map.find(name); if (eit != E_Map.end()) return eit->second; e = new Edge; e->name = name; e->n1 = n1; e->n2 = n2; e->original = 0; e->residual = 0; e->flow = 0; e->reverse = NULL; Edges.push_back(e); E_Map.insert(make_pair(name, e)); return e; } main(int argc, char **argv) { Graph *g; int f; if (argc > 2 || argc == 2 && strcmp(argv[1], "Print") != 0) { fprintf(stderr, "usage: netflow [Print]\n"); exit(1); } g = new Graph(); g->Print_Paths = (argc == 2); f = g->Find_Max_Flow(); printf("Max flow is %d\n", f); }