Cod sursa(job #120537)

Utilizator sima_cotizoSima Cotizo sima_cotizo Data 5 ianuarie 2008 20:27:50
Problema Gather Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.26 kb
#include <cstdio>
#include <cstring>
#include <utility>
#include <list>
using namespace std;

#define f first
#define s second

const long MAX_K = 16;
const long MAX_N = 760;
const long MAX_M = 1260;

inline long min(long a, long b) { return (a<b)?a:b; }
inline long nr_biti(long a) { for (long nr=0; true; a>>=1) { if ( a==0 ) return nr; nr += (a&1); } }


struct nod {
	long x, mask;
};

template <typename tip, typename store> 
struct muchie {
	tip x,y;
	store inf;
};

long K,N,M;
long start[MAX_K];
muchie<long, pair<long, long> > A[MAX_M];	// first = lungimea, second = capacitatea;
list< muchie<nod, long> > B;
long C[MAX_N][1<<MAX_K];

long D[MAX_K][MAX_N];


void bellman(long x, long m) {		// imi pune costul minim din x in i prin muchii de capac >= m
	memset(D[m],0x3f, sizeof(D[m]));
	D[m][x] = 0;

	for (long count=0; true /*count<N-1*/; ++count) {
		bool merge=false;

		for (long i=0; i<M; ++i) 
			if ( A[i].inf.s >= m ) {
				long st = A[i].x, dr = A[i].y, v = A[i].inf.f;
				if ( D[m][dr] > D[m][st]+v )
					D[m][dr] = D[m][st]+v, merge = true;
				if ( D[m][st] > D[m][dr]+v )
					D[m][st] = D[m][dr]+v, merge = true;
			}

		if ( !merge ) 
			break;
	}
}


int main() {
	long i,j;

	freopen("gather.in", "r", stdin);
	scanf("%ld %ld %ld", &K, &N, &M);
	for (i=0; i<K; ++i) scanf("%ld", start+i);
	for (i=0; i<M; ++i) scanf("%ld %ld %ld %ld", &A[i].x, &A[i].y, &A[i].inf.f, &A[i].inf.s);
	fclose(stdin);

	for (j=0; j<=K; ++j)
		bellman(1,j);

	for (long ms=0; ms<(1<<K)-1; ++ms) {
		long nm = nr_biti(ms);
		for (j=0; j<K; ++j) {
			if ( (ms & (1<<j)) == 0 ) {
				if ( D[nm][start[j]] >= 0x3f3f3f3f )
					continue;
				muchie<nod, long> tmp;
				tmp.x.x=1, tmp.x.mask=ms;
				tmp.y.x=start[j], tmp.y.mask=ms+(1<<j);
				tmp.inf = D[nm][start[j]];

				B.push_back(tmp);
			}
		}
	}



	for (i=0; i<K; ++i) {
		if ( start[i]==1 ) continue;	// pe 1 il prelucram separat.

		for (j=1; j<=K; ++j) {
			bellman(start[i],j);
		}

		for (long ms=1; ms<(1<<K)-1; ++ms) {
			long nm = nr_biti(ms);
			for (j=0; j<K; ++j) {
				if ( (ms & (1<<j)) == 0 ) {
					if ( D[nm][start[j]] >= 0x3f3f3f3f || i==j )
						continue;
					muchie<nod, long> tmp;
					tmp.x.x=start[i], tmp.x.mask=ms;
					tmp.y.x=start[j], tmp.y.mask=ms+(1<<j);
					if ( ms==0 )
						tmp.inf = D[1][start[j]];
					else
						tmp.inf = D[nm][start[j]];

					B.push_back(tmp);
				}
			}
		}
	}
	
	// Totul OK pana aici
/*	for (list< muchie<nod, long> >::iterator it=B.begin(); 	it!=B.end(); ++it) {
		muchie<nod, long> tmp = *it;
		printf("(%ld,%ld) -> (%ld,%ld) = %ld\n", tmp.x.x, tmp.x.mask, tmp.y.x, tmp.y.mask, tmp.inf);
	}
*/

	memset(C, 0x3f, sizeof(C));
	C[1][0] = 0;

	list< muchie<nod,long> >::iterator it;
	for (long count=0; true; count++) {
		bool merge = false;
		for (it=B.begin(); it!=B.end(); ++it) {
			muchie<nod, long> tmp = *it;
			long nr = nr_biti(tmp.x.mask)+1;
			if ( C[tmp.y.x][tmp.y.mask] > C[tmp.x.x][tmp.x.mask]+tmp.inf*nr ) {
				C[tmp.y.x][tmp.y.mask] = C[tmp.x.x][tmp.x.mask]+tmp.inf*nr, merge=true;
//				printf("Upgrade C[%ld][%ld] = %ld, from (%ld,%ld)\n", tmp.y.x, tmp.y.mask, C[tmp.y.x][tmp.y.mask], tmp.x.x, tmp.x.mask);
			}
		}

		if ( !merge ) break;
	}

	long raspuns=0x3f3f3f3f;
	for (i=1; i<=N; ++i)
		raspuns = min(raspuns, C[i][(1<<K)-1]);

	fprintf(fopen("gather.out","w"), "%ld\n", raspuns);
	return 0;
}