Cod sursa(job #32052)

Utilizator eferLiviu Ciortea efer Data 17 martie 2007 11:29:45
Problema Cc Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.3 kb
#include <cstdio>
#include <algorithm>
#include <utility>
using namespace std;

const int NMAX = 256;
const int MMAX = 256;
const int INF = 0x3f3f3f3f;
int N, M, pot[NMAX+MMAX], cst[NMAX][MMAX];
int matchA[NMAX], matchB[MMAX];

int augment(int source) {
	bool used[NMAX+MMAX];
	memset(used, 0, sizeof(used));
	int dst[NMAX+MMAX];
	memset(dst, 0x3f, sizeof(dst));
	dst[source] = 0;
	int last[NMAX+MMAX];
	memset(last, -1, sizeof(last));

	for (int step = 0; step < N+M; ++step) {
		int minDst = INF, pos = -1;
		for (int i = 0; i < N+M; ++i) {
			if (!used[i] && minDst > dst[i]) {
				minDst = dst[pos = i];
			}
		}
		if (pos == -1) break;
		used[pos] = true;

		if (pos < N) { // forward edges
			for (int i = 0; i < M; ++i) {
				if (used[N+i] || cst[pos][i] == INF) continue;
				int ndst = dst[pos] + cst[pos][i] + pot[pos] - pot[N+i];
				if (ndst < dst[N+i]) {
					dst[N+i] = ndst;
					last[N+i] = pos;
				}
			}
		} else { // backwards edge
			int next = matchB[pos-N];
			if (next == -1 || used[next]) continue;
			int ndst = dst[pos] - cst[next][pos-N] + pot[pos] - pot[next];
			if (ndst < dst[next]) {
				dst[next] = ndst;
				last[next] = pos;
			}
		}
	}

	for (int i = 0; i < N+M; ++i)
		if (dst[i] < INF) pot[i] += dst[i];

	int minDst = INF, where = -1;
	for (int i = 0; i < M; ++i) {
		if (matchB[i] == -1 && minDst > dst[N+i]) {
			minDst = dst[where = N+i];
		}
	}

	int minCst = 0;
	while (where != -1) {
		int next = last[where];
		if (where >= N) { // match
			matchA[next] = where-N;
			matchB[where-N] = next;
			minCst += cst[next][where-N];
		} else {
			if (next != -1) minCst -= cst[where][next-N];
		}
		where = next;
	}

	return minCst;
}

pair<int, int> minCostBipartiteMatch() {
	memset(pot, 0, sizeof(pot));
	memset(matchA, -1, sizeof(matchA));
	memset(matchB, -1, sizeof(matchB));

	int num = 0, cost = 0;
	for (int i = 0; i < N; ++i) {
		int mcost = augment(i);
		if (mcost < INF) {
			cost += mcost;
			num++;
		}
	}
	return make_pair(num, cost);
}

int main() {
	freopen("cc.in", "rt", stdin);
	freopen("cc.out", "wt", stdout);

	scanf("%d", &N);
	M = N;
	for (int i = 0; i < N; ++i)
		for (int j = 0; j < M; ++j)
			scanf("%d", &cst[i][j]);

	printf("%d\n", minCostBipartiteMatch().second);

	return 0;
}