Cod sursa(job #115472)

Utilizator ProstuStefan-Alexandru Filip Prostu Data 16 decembrie 2007 12:48:24
Problema Gather Scor 80
Compilator cpp Status done
Runda preONI 2008, Runda 2, Clasele 11-12 Marime 2.39 kb
// O( K*N*M + K^2 * 2^K )
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>

using namespace std;

#define PB push_back

const unsigned INF = 0xffffffff;
const int NMAX = 1024;
const int KMAX = 16;

struct edge {
	int v;
	unsigned c, d;
	edge(int _v = 0, unsigned _c = 0, unsigned _d = 0) : v(_v), c(_c), d(_d) {}
	bool operator<(const edge &a) const {
		return d > a.d;
	}
};

int K, N, M;
int P[KMAX];
vector <edge> G[NMAX];
int Dist[KMAX][KMAX][KMAX];
bool B[KMAX][1 << KMAX];
unsigned O[KMAX][1 << KMAX];

void read(void) {
	FILE *fin = fopen("gather.in", "rt");
	int i, a, b;
	unsigned c ,d;

	fscanf(fin, " %d %d %d", &K, &N, &M);

	for (i = 0; i < K; ++i)
		fscanf(fin, " %d", &P[i]);

	for (i = 0; i < M; ++i) {
		fscanf(fin, " %d %d %u %u", &a, &b, &c, &d);

		G[a].PB( edge(b, c, d) );
		G[b].PB( edge(a, c, d) );
	}

	fclose(fin);
}

void bellmanFord(void) {
	int i, j, k, u;
	vector <edge> :: iterator it;
	bool V[NMAX];
	unsigned D[NMAX];
	queue <int> Q;

	for (i = 1; i <= N; ++i)
		sort(G[i].begin(), G[i].end());

	P[K] = 1;
	for (i = 0; i <= K; ++i) {
		
		memset(D, 0xff, sizeof(D));

		D[P[i]] = 0;

		for (j = K; j >= 0; --j) {
			
			for (k = 1; k <= N; ++k)
				V[k] = true,
				Q.push(k);

			for (; !Q.empty(); Q.pop()) {
				u = Q.front();
				V[u] = false;

				for (it = G[u].begin(); it != G[u].end() && it->d >= (unsigned)j; ++it) {
					if ((long long)D[u] + it->c >= D[it->v])
						continue;
					D[it->v] = D[u] + it->c;

					if (V[it->v] == true)
						continue;

					V[it->v] = true;
					Q.push(it->v);

				}
			}

			for (k = 0; k < K; ++k) {
				if ((long long) D[P[k]] * (j + 1) < INF)
					Dist[j][i][k] = D[P[k]] * (j + 1);
				else
					Dist[j][i][k] = INF;
			}
		}

	}
}

unsigned solve(int k, int cnf, int mlt) {
	if (mlt == 0)
		return Dist[0][K][k];
	if (B[k][cnf] == true)
		return O[k][cnf];
	
	int i;
	unsigned rez = INF, t;

	for (i = 0; i < K; ++i)
		if (cnf & (1 << i)) {
			t = solve(i, cnf & ~(1 << i), mlt - 1);
			if ((long long) t + Dist[mlt][k][i] < INF)
				t += Dist[mlt][k][i];
			else
				t = INF;
			rez = min(rez, t);
		}

	B[k][cnf] = true;
	return O[k][cnf] = rez;
}

void write(void) {
	FILE *fout = fopen("gather.out", "wt");
	int i;
	unsigned rez;

	rez = INF;
	for (i = 0; i < K; ++i)
		rez = min(rez, solve(i, (1 << K) - 1, K));

	fprintf(fout, "%u\n", rez);

	fclose(fout);
}

int main(void) {

	read();

	bellmanFord();

	write();

	return 0;
}