Pagini recente » Cod sursa (job #1274922) | Cod sursa (job #2070408) | Cod sursa (job #940506) | Cod sursa (job #528473) | Cod sursa (job #2958297)
#include <fstream>
#include <limits>
#include <queue>
#include <vector>
using std::vector;
using Node = int;
const int INF = std::numeric_limits<int>::max();
class FlowNetwork {
private:
int nodeCount;
vector<vector<int>> capacityMatrix;
vector<vector<Node>> adjList;
void buildBfsTree(Node s, Node t, vector<Node> &prevInTree) {
std::fill(prevInTree.begin(), prevInTree.end(), -1);
prevInTree[s] = -2;
std::queue<Node> bfsQueue;
bfsQueue.push(s);
while (!bfsQueue.empty()) {
auto node = bfsQueue.front();
bfsQueue.pop();
for (Node next: adjList[node]) {
// Skip visited nodes and saturated edges
if (prevInTree[next] != -1 || capacityMatrix[node][next] == 0)
continue;
if (next == t)
continue;
prevInTree[next] = node;
bfsQueue.push(next);
}
}
}
/// Find the minimum capacity through the path from start to end
int findMinFlowThroughPath(Node start, Node end, vector<Node> &prevInPath) {
int flow = INF;
Node current = end;
while (current != start) {
Node prevNode = prevInPath[current];
flow = std::min(flow, capacityMatrix[prevNode][current]);
current = prevNode;
}
return flow;
}
/// Update the flows through the path from start to end with the given value
void updateFlowThroughPath(Node start, Node end, vector<Node> &prevInPath, int flow) {
Node current = end;
while (current != start) {
Node prev = prevInPath[current];
capacityMatrix[prev][current] -= flow;
capacityMatrix[current][prev] += flow;
current = prev;
}
}
/// Try to find an augmenting path and return the added flow
int tryAugmentFlow(Node s, Node t, vector<Node> &prevInTree) {
buildBfsTree(s, t, prevInTree);
int totalAugmentingFlow = 0;
// For each node just before t, join it with t and use that as an augmenting path
for (Node nodeBeforeT: adjList[t]) {
// Skip node if it was unreachable due to saturation
if (prevInTree[nodeBeforeT] == -1)
continue;
// Join nodeBeforeT and t and update the capacities through the path
prevInTree[t] = nodeBeforeT;
auto minFlowThroughPath = findMinFlowThroughPath(s, t, prevInTree);
updateFlowThroughPath(s, t, prevInTree, minFlowThroughPath);
totalAugmentingFlow += minFlowThroughPath;
}
return totalAugmentingFlow;
}
public:
struct Edge {
Node from;
Node to;
};
explicit FlowNetwork(int nodeCount) : nodeCount(nodeCount) {
capacityMatrix.resize(nodeCount, vector<int>(nodeCount));
adjList.resize(nodeCount);
}
void addEdge(Node from, Node to, int capacity) {
adjList[from].push_back(to);
adjList[to].push_back(from);
capacityMatrix[from][to] = capacity;
}
const vector<Node> &getNeighbors(Node from) {
return adjList[from];
}
int computeMaxFlow(Node s, Node t) {
int maxFlow = 0;
vector<Node> prevInPath(nodeCount);
int newFlow;
while ((newFlow = tryAugmentFlow(s, t, prevInPath)) > 0) {
maxFlow += newFlow;
}
return maxFlow;
}
int getEdgeFlow(Node from, Node to) {
return capacityMatrix[from][to];
}
};
int main() {
std::ifstream in("cuplaj.in");
int fromCount, toCount, edgeCount;
in >> fromCount >> toCount >> edgeCount;
int nodeCount = fromCount + toCount + 1;
FlowNetwork network(nodeCount + 1);
for (int i = 1; i <= edgeCount; ++i) {
Node from, to;
in >> from >> to;
network.addEdge(from, to + fromCount, 1);
}
in.close();
// Connect s and t to the two partitions
Node s = 0;
Node t = nodeCount;
for (Node from = 1; from <= fromCount; ++from) {
network.addEdge(s, from, 1);
}
for (Node to = 1; to <= toCount; ++to) {
network.addEdge(to + fromCount, t, 1);
}
std::ofstream out("cuplaj.out");
out << network.computeMaxFlow(s, t) << '\n';
for (Node from = 1; from <= fromCount; ++from) {
for (Node to : network.getNeighbors(from)) {
if (to == s) continue;
if (network.getEdgeFlow(from, to) == 0) {
out << from << ' ' << to - fromCount << '\n';
}
}
}
out.close();
return 0;
}