Cod sursa(job #133548)

Utilizator silviugSilviu-Ionut Ganceanu silviug Data 8 februarie 2008 21:55:59
Problema Paznici2 Scor Ascuns
Compilator cpp Status done
Runda Marime 3.23 kb
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <cmath>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <utility>
#include <string>
#include <stack>
using namespace std;

#define REP(i, N) for (int i = 0; i < (N); ++i)
#define REPV(i, a, b) for (int i = (a); i <= (b); ++i)
#define REPD(i, N) for (int i = (N)-1; i >= 0; --i)
#define REPVD(i, b, a) for (int i = (b); i >= (a); --i)
#define REPIT(it, v) for (it = (v).begin(); it != (v).end(); ++it)
#define SZ(a) ((int)(a).size())
#define MP make_pair
#define PB push_back
#define X first
#define Y second
#define ALL(a) (a).begin(), (a).end()
#define CLR(a) memset((a), 0, sizeof(a))
#define MSET(a, v) memset((a), v, sizeof(a))
#define CPY(dest, source) memcpy(dest, source, sizeof(dest))

typedef long long LL;
typedef vector<int> VI;
typedef vector<string> VS;
typedef pair<int, int> PII;

const int MAXN = 256;
int N, cost[2*MAXN][2*MAXN], cap[2*MAXN][2*MAXN], dst[MAXN+MAXN], from[MAXN+MAXN], match[MAXN], sink;
bool can[MAXN][MAXN];
set<int> sol[MAXN];

bool do_the_monkey(int source, bool mode) {
	bool seen[MAXN+MAXN];
	CLR(seen);
	seen[source] = true;

	MSET(dst, 0x3f);
	dst[source] = 0;
	MSET(from, -1);

	deque<int> Q;
	Q.PB(source);


	while (!Q.empty()) {
		int r = Q.front(); Q.pop_front();
		seen[r] = false;

		REP(i, sink+1) {
			if (!cap[r][i]) continue;
			int now = dst[r] + cost[r][i];
			if (now < dst[i]) {
				dst[i] = now;
				from[i] = r;
				if (!seen[i]) {
					Q.PB(i);
					seen[i] = true;
				}
			}
		}

		if (mode && dst[match[source]] == cost[source][match[source]]) return true;
	}

	return false;
}

int get_path_cost(int source) {
	int who = sink;
	while (who != source) {
		cap[from[who]][who]--;
		cap[who][from[who]]++;
		who = from[who];
	}
	return dst[sink];
}

void update(int source) {
	int r = match[source];
	cap[r][source] = 0;

	while (r != source) {
		cap[from[r]][r]--;
		cap[r][from[r]]++;
		if (from[r] < N) {
			sol[r-N].insert(from[r]);
			can[from[r]][r-N] = true;
			match[from[r]] = r;
		}
		r = from[r];
	}
}

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

	scanf("%d", &N);
	sink = 2*N;

	REP(i, N) REP(j, N) {
		scanf("%d", &cost[i][j+N]);
		cost[j+N][i] = -cost[i][j+N];
		cap[i][j+N] = 1;
	}

	REP(i, N) cap[i+N][sink] = 1;

	int total_cost = 0;

	REP(i, N) {
		do_the_monkey(i, false);
		total_cost += get_path_cost(i);
	}

	REP(i, N) {
		REP(j, N) {
			if (!cap[i][j+N]) {
				match[i] = j+N;
				can[i][j] = true;
				sol[j].insert(i);
				break;
			}
		}
	}

	printf("%d\n", total_cost);

	REP(i, N) {
		REP(j, N) if (can[i][j]) cap[i][j+N] = 0;

		for (;;) {
			if (!do_the_monkey(i, true)) break;
			update(i);

			//int sum = 0;
			//REP(j, N) sum += cost[j][match[j]];
			//assert(sum == total_cost);
		}

		REP(j, N) if (match[i] != j+N) {
			//if (can[i][j]) assert(cap[i][j+N] == 0);
			cap[i][j+N] = 1;
		}
	}

	REP(i, N) {
		printf("%d", SZ(sol[i]));
		set<int>::iterator it;
		REPIT(it, sol[i]) printf(" %d", *it + 1);
		printf("\n");
	}

	return 0;
}