Cod sursa(job #115464)

Utilizator victorsbVictor Rusu victorsb Data 16 decembrie 2007 12:47:30
Problema Gather Scor 20
Compilator cpp Status done
Runda preONI 2008, Runda 2, Clasele 11-12 Marime 3.21 kb
#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

#define Nmax 768
#define Kmax 16
#define Mmax 1265
#define INF 0x3f3f3f3f
#define x first
#define y second
#define mp make_pair
#define pb push_back
#define sz(a) (int)((a).size())

struct muchie
{
	int a, b, c, d;
};

int n, m, k, hs;
int p[Kmax];
muchie muc[Mmax];
int dist[1 << 15][Kmax];
int h[Nmax];
int ind[Nmax];
vector< pair<int, int> > lv[Nmax];
int d[Nmax];
int mat[Kmax][Kmax][Kmax];

void citire()
{
	int i;

	scanf("%d %d %d\n", &k, &n, &m);

	for (i = 1; i <= k; ++i)
		scanf("%d\n", &p[i]);

	for (i = 1; i <= m; ++i)
		scanf("%d %d %d %d\n", &muc[i].a, &muc[i].b, &muc[i].c, &muc[i].d);
}

int cmp(const muchie p1, const muchie p2)
{
	return (p1.d > p2.d);
}

inline void combheap(int i)
{
	int tata = i;
	int fiu = tata * 2;

	while (fiu <= hs)
	{
		if (fiu < hs && d[h[fiu]] > d[h[fiu + 1]]) ++fiu;
		if (d[h[tata]] <= d[h[fiu]]) break;
		swap(h[tata], h[fiu]);
		ind[h[tata]] = tata;
		ind[h[fiu]] = fiu;

		tata = fiu;
		fiu = tata * 2;
	}
}

inline void update(int i)
{
	int fiu = i;
	int tata = fiu / 2;

	while (tata)
	{
		if (d[h[tata]] < d[h[fiu]]) break;
		swap(h[tata], h[fiu]);
		ind[h[tata]] = tata;
		ind[h[fiu]] = fiu;

		fiu = tata;
		tata = fiu / 2;
	}
}

inline int extract_min()
{
	int ret = h[1];

	h[1] = h[hs--];
	ind[h[1]] = 1;
	combheap(1);

	return ret;
}

void dijkstra(int s)
{
	int i, j, nod;

	memset(d, 0x3f, sizeof(d));
	d[s] = 0;

	hs = n;
	for (i = 1; i <= n; ++i)
		h[i] = ind[i] = i;

	for (i = hs / 2; i >= 1; --i)
		combheap(i);

	for (i = 1; i <= n; ++i)
	{
		nod = extract_min();

		for (j = 0; j < sz(lv[nod]); ++j)
			if (d[lv[nod][j].x] > d[nod] + lv[nod][j].y)
			{
				d[lv[nod][j].x] = d[nod] + lv[nod][j].y;
				update(ind[d[lv[nod][j].x]]);
			}
	}
}

void solve()
{
	int i, last = 1, j, l, ct, mask, sol = INF;

	sort(muc+1, muc+m+1, cmp);
	for (i = k; i >= 0; --i)
	{
		while (last <= m && muc[last].d >= i)
		{
			lv[muc[last].a].pb(mp(muc[last].b, muc[last].c));
			lv[muc[last].b].pb(mp(muc[last].a, muc[last].c));
			++last;
		}

        for (j = 1; j <= k; ++j)
		{
			dijkstra(p[j]);

			for (l = 1; l <= k; ++l)
				mat[j][l][i] = d[p[l]];
		}
	}

    dijkstra(1);

	memset(dist, 0x3f, sizeof(dist));
	for (i = 1; i <= k; ++i)
		dist[0][i] = d[p[i]];

	/*
	for (l = 0; l <= k; ++l)
	{
		for (i = 1; i <= k; ++i)
		{
			for (j = 1; j <= k; ++j)
				printf("%d ", mat[i][j][l]);
			printf("\n");
		}
		printf("\n");
	}
	*/

	for (mask = 0; mask < 1 << k; ++mask)
	{
		ct = 0;
		for (i = 0; i < k; ++i)
			ct += ((mask >> i) & 1);

		for (i = 1; i <= k; ++i)
		{
			for (j = 1; j <= k; ++j)
				if (!((mask >> (j - 1)) & 1) && mat[i][j][ct] != INF)
					if (dist[mask + (1 << (j - 1))][j] > dist[mask][i] + (ct + 1) * mat[i][j][ct])
					{
						dist[mask + (1 << (j - 1))][j] = dist[mask][i] + (ct + 1) * mat[i][j][ct];
						//if (mask + (1 << (j - 1)) == 12 && j == 3) printf("aici - %d %d - %d\n", mask, i, dist[mask][i]);
					}
			//printf("%d %d -> %d\n", i, mask, dist[mask][i]);
		}
	}

	for (i = 1; i <= k; ++i)
		if (sol > dist[(1 << k) - 1][i])
			sol = dist[(1 << k) - 1][i];

	printf("%d\n", sol);
}

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

	citire();
	solve();

	return 0;
}