Cod sursa(job #115333)

Utilizator gcosminGheorghe Cosmin gcosmin Data 16 decembrie 2007 12:12:19
Problema Gather Scor 10
Compilator cpp Status done
Runda preONI 2008, Runda 2, Clasele 11-12 Marime 2.04 kb
#include <stdio.h>
#include <vector>
using namespace std;

#define NMAX 760
#define KMAX 20
#define MP make_pair
#define ff first
#define ss second
#define uint unsigned int
#define INF 1000000000

int K, N, M;

int dist[KMAX][KMAX][KMAX];

int dc[NMAX];

int poz[KMAX];

vector <pair<int, pair<int, int> > > leg[NMAX];

int coada[NMAX * NMAX];
char in_coada[NMAX];

int din[(1 << 16) + 10][KMAX];

int nrb(int x)
{
	int rez = 0;

	while (x) {
		rez++;
		x &= x - 1;
	}

return rez;
}

inline int MIN(int a, int b) { return (a < b) ? a : b; }

int calc_dist(int jeg, int nd)
{
	int i, x, y, p, q, c, d;

	for (i = 1; i <= N; i++) dc[i] = INF;

	dc[ poz[jeg] ] = 0;
	p = 0, q = 0;
	coada[0] = poz[jeg];

	vector <pair<int, pair<int, int> > > :: iterator it;
	while (p <= q) {
		x = coada[p];
		p++;
		in_coada[x] = 0;

		for (it = leg[x].begin(); it != leg[x].end(); ++it) {
			y = it->ff; c = it->ss.ff; d = it->ss.ss;
			if (d < nd) continue;

			if (dc[x] + c < dc[y]) {
				dc[y] = dc[x] + c;
				if (!in_coada[y]) {
					coada[++q] = y;
					in_coada[y] = 1;
				}
			}
		}
	}

	for (i = 1; i <= K; i++) dist[nd][jeg][i] = dc[poz[i]];

return 0;
}


int main()
{
	int i, x, y, c, d, j, k;

	freopen("gather.in", "r", stdin);
	freopen("gather.out", "w", stdout);

	scanf("%d %d %d", &K, &N, &M);

	for (i = 1; i <= K; i++) scanf("%d", &poz[i]);

	for (i = 1; i <= M; i++) {
		scanf("%d %d %d %d", &x, &y, &c, &d);

		leg[x].push_back(MP(y, MP(c, d)));
		leg[y].push_back(MP(x, MP(c, d)));
	}

	poz[0] = 1;
	for (i = 0; i <= K; i++) 
		for (j = 1; j <= K; j++) calc_dist(i, j);

	for (i = 0; i < (1 << K); i++)
		for (j = 0; j <= K; j++) din[i][j] = INF;

	din[0][0] = 0;

	for (i = 0; i < (1 << K); i++) 
		for (j = 0; j <= K; j++) {
			if (din[i][j] == INF) continue;

			for (k = 1; k <= K; k++) {
				if ((1 << (k - 1)) & i) continue;

				din[i | (1 << (k - 1))][k] = MIN(din[i | (1 << (k - 1))][k], din[i][j] + (nrb(i) + 1) * dist[nrb(i) + 1][j][k]);
			}
		}

	int rez = INF;
	for (j = 1; j <= K; j++) 
		rez = MIN(rez, din[(1 << K) - 1][j]);

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

return 0;
}