Cod sursa(job #116000)

Utilizator MariusMarius Stroe Marius Data 17 decembrie 2007 16:22:37
Problema Gather Scor 50
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.64 kb
#include <cstdio>
#include <vector>
#include <memory.h>

using namespace std;

const char iname[] = "gather.in";
const char oname[] = "gather.out";

#define MAXK  16
#define MAXSTATE  1 << MAXK
#define MAXN  755
#define INF   int(1e9)
#define swap(a, b) ((a) ^= (b) ^= (a) ^= (b))

int K, N, M;

int C[MAXSTATE][MAXK], P[MAXK];

struct tlist_node {
	int nod, cst, cap;
	void update(int nod, int cst, int cap) {
		this->nod = nod;
		this->cst = cst;
		this->cap = cap;
	}
} ;

vector <tlist_node> G[MAXN];

int D[MAXN], H[MAXN], W[MAXN], size;

bool in[MAXN], out[MAXN];


void down(int i) 
{
	for (int done = 0; !done; ) {
		int l = 2 * i;
		int r = 2 * i + 1;
		int k = i;
		if (l <= size && D[H[l]] < D[H[k]])
			k = l;
		if (r <= size && D[H[r]] < D[H[k]])
			k = r;
		if (k == i)  
			done = 1;
		else
			swap(H[k], H[i]), i = k;
	}
}

void up(int i) 
{
	while (i > 1 && D[H[i >> 1]] > D[H[i]])
		swap(H[i], H[i >> 1]), W[H[i]] = i, i >>= 1;
	W[H[i]] = i;
}

void insert(int n)
{
	in[n] = true;
	++ size;
	H[size] = n;
	W[n] = size;
	up(size);
}

int getmin(void)
{
	int n = H[1];
	H[1] = H[size --];
	W[H[1]] = 1;
	out[n] = true;
	if (size > 1)
		down(1);
	return n;
}

int deplaseaza(int srs, int dst, int cnt)
{
	vector <tlist_node>::iterator it;

	for (int i = 1; i <= N; ++ i) {
		in[i] = out[i] = false;
		W[i] = 0;
		D[i] = INF;
	}
	size = 0;
	for (D[srs] = 0, insert(srs); ; )
	{
		int x = getmin();
		if (x == dst)
			return D[dst];
		for (it = G[x].begin(); it != G[x].end(); ++ it) if (it->cap >= cnt)
			if (!out[it->nod])	if (D[it->nod] > D[x] + it->cst) {
				D[it->nod] = D[x] + it->cst;
				if (!in[it->nod])
					insert(it->nod);
				else
					up(W[it->nod]);
			}
	}
}		

int f(int s, int p)
{
	if (C[s][p] != -1)	return C[s][p];

	if (s & (s - 1)) 
	{	// sunt cel putin doi detinuti
		int cnt = 0;
		for (int i = 0; i < K; ++ i) if ((s >> i) & 1)
			cnt ++;
		int t = s ^ (1 << p);
		for (int i = 0; i < K; ++ i) if ((t >> i) & 1)
		{
			int res = f(t, i) + cnt * deplaseaza(P[i], P[p], cnt - 1);
			if (C[s][p] == -1 || C[s][p] > res)
				C[s][p] = res;
		}
	} else
		C[s][p] = deplaseaza(1, P[p], 0);

	return C[s][p];
}

int main(void)
{
	freopen(iname, "r", stdin);
	freopen(oname, "w", stdout);

	int x, y, cst, cap;
	
	scanf("%d %d %d", &K, &N, &M);
	for (int i = 0; i < K; ++ i)
		scanf("%d", &P[i]);
	tlist_node t;
	for (int i = 0; i < M; ++ i) {
		scanf("%d %d %d %d", &x, &y, &cst, &cap);
		t.update(y, cst, cap);
		G[x].push_back(t);
		t.update(x, cst, cap);
		G[y].push_back(t);
	}
	memset(C, -1, sizeof(C));

	int ans = -1;
	for (int i = 0; i < K; ++ i) {
		if (ans == -1 || ans > f((1 << K) - 1, i))
			ans = f((1 << K) - 1, i);
	}
	printf("%d\n", ans);

	return 0;
}