Cod sursa(job #1983367)

Utilizator SlevySlevoaca Stefan-Gabriel Slevy Data 21 mai 2017 19:30:09
Problema Cuplaj maxim in graf bipartit Scor 80
Compilator cpp Status done
Runda Arhiva educationala Marime 3.26 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <bitset>
#define NMAX 20003
#define EMAX 100100
#define min(x, y) ((x < y) ? x : y)

using namespace std;

ifstream in("cuplaj.in");
ofstream out("cuplaj.out");

struct edge {

	int X, Y, cap, flow;
	edge(int x = 0, int y = 0, int c = 0, int f = 0) : X(x), Y(y), cap(c), flow(f) {}
};

edge edges[EMAX];
unsigned int nr_edges = 0;

struct triplet {

	int Y;
	edge *dir, *rev;
	triplet(int y = 0, edge *DIR = nullptr, edge *REV = nullptr) : Y(y), dir(DIR), rev(REV) {}
};

vector<triplet> G[NMAX];
bitset<NMAX> mark;
queue<int> q;
int left_size, right_size;
pair<int, triplet*> father[NMAX];
int n;

void build_graph() {

	int m, x, y;
	edge *dir, *rev;
	in >> left_size >> right_size >> m;
	n = left_size + right_size + 2;

	for (int i = 1; i <= m; i++) {

		in >> x >> y;
		edges[++nr_edges] = edge(x + 1, y + left_size + 1, 1, 0);
		dir = &edges[nr_edges];
		edges[++nr_edges] = edge(y + left_size + 1, x + 1, 0, 0);
		rev = &edges[nr_edges];

		G[x + 1].push_back(triplet(y + left_size + 1, dir, rev));
		G[y + left_size + 1].push_back(triplet(x + 1, rev, dir));
	}

	for (int i = 2; i < 2 + left_size; i++)
	{
		edges[++nr_edges] = edge(1, i, 1, 0);
		dir = &edges[nr_edges];
		edges[++nr_edges] = edge(i, 1, 0, 0);
		rev = &edges[nr_edges];

		G[1].push_back(triplet(i, dir, rev));
		G[i].push_back(triplet(1, rev, dir));
	}

	for (int i = left_size + 2; i < n; i++)
	{
		edges[++nr_edges] = edge(i, n, 1, 0);
		dir = &edges[nr_edges];
		edges[++nr_edges] = edge(n, i, 0, 0);
		rev = &edges[nr_edges];

		G[i].push_back(triplet(n, dir, rev));
		G[n].push_back(triplet(i, rev, dir));
	}
}

void bfs(int start) {

	mark.reset();
	q.push(start);
	mark.set(start);
	father[start] = make_pair(0, nullptr);

	int node;

	while (!q.empty()) {

		node = q.front();

		for (unsigned int i = 0; i < G[node].size(); i++)
			if (!mark.test(G[node][i].Y) && G[node][i].dir->cap > G[node][i].dir->flow) {

				q.push(G[node][i].Y);
				mark.set(G[node][i].Y);
				father[G[node][i].Y] = make_pair(node, &G[node][i]);
			}

		q.pop();
	}
}

int main() {
	
	build_graph();
	
	int node = 0, val;
	int max_flow = 0;

	for (bfs(1); mark.test(n); bfs(1)) {

		for (unsigned int i = 0; i < G[n].size(); i++)
			if (mark.test(G[n][i].Y) && G[n][i].rev->cap > G[n][i].rev->flow) {

				node = G[n][i].Y;
				val = 2;

				while (node != 0)
				{
					if (father[node].first != 0)
						val = min(val, father[node].second->dir->cap - father[node].second->dir->flow);
					node = father[node].first;
				}

				node = G[n][i].Y;
				val = min(val, G[n][i].rev->cap - G[n][i].rev->flow);
				max_flow += val;

				while (node != 0)
				{
					if (father[node].first != 0)
					{
						father[node].second->dir->flow += val;
						father[node].second->rev->flow -= val;
					}
					node = father[node].first;
				}

				G[n][i].rev->flow += val;
				G[n][i].dir->flow -= val;
			}
	}

	out << max_flow << "\n";

	for (int i = 2; i <= n - 1; i++)
		for (unsigned int j = 0; j < G[i].size(); j++)
			if (G[i][j].dir->flow == 1 && G[i][j].Y != n)
				out << i - 1 << " " << G[i][j].Y - left_size - 1 << "\n";

	return 0;

}