Cod sursa(job #1490041)

Utilizator theprdvtheprdv theprdv Data 22 septembrie 2015 17:41:30
Problema Gather Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.12 kb
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#define DIM (1 << 13)
#define MAXN 752
#define MAXM 1252
#define MAX(x, y) ( ((x) > (y)) ? (x) : (y) )
#define MIN(x, y) ( ((x) < (y)) ? (x) : (y) )
#define foreach(V) for(edge *it = (V); it; it = it->link)
#define INF ((1 << 31) * 2 - 1)

int K, N, M, __K[16], pos, len;
unsigned int pr_dist[16][16][16], // pr[i][j][k] -> distance from __K[i] to __K[j] through edges of capacity >= k
			dist[MAXN], comb[16][1 << 15];
bool prisoner[MAXN];
char buf[DIM];

struct edge{
	short int node;
	char maxCnt;
	unsigned int cost;
	edge *link;

	inline edge *new_edge(short int _node, char _maxCnt, int _cost){
		edge *New = new edge;
		New->node = _node, New->maxCnt = _maxCnt, New->cost = _cost, New->link = this;
		return New;
	}
} *G[MAXN]; // the graph edges

int size; // size of heap
struct heap_elem{
	short int node;
	unsigned int cost;
} Heap[MAXM];

inline int r_int32(){
	while (buf[pos] < '0' || buf[pos] > '9'){
		if (++pos >= DIM) len = fread(buf, 1, DIM, stdin), pos = 0;
	}
	int val = 0;

	while (buf[pos] >= '0' && buf[pos] <= '9'){
		if (pos == len) break;
		val = val * 10 + buf[pos] - '0';
		if (++pos == DIM) len = fread(buf, 1, DIM, stdin), pos = 0;
	}
	return val;
}

inline void w_int32(int k){
	char lim[16], *s;
	s = lim + 15, *s = 0;

	do{
		*--s = k % 10 + '0';
		k /= 10;
	} while (k);
	puts(s);
}


inline void heap_pop(){
	Heap[1] = Heap[size--];
	
	heap_elem curr = Heap[1];
	short int now = 1, next = 2;
	if (next + 1 <= size && Heap[next + 1].cost < Heap[next].cost) ++next;
	
	while (next <= size && Heap[now].cost > Heap[next].cost){
		Heap[now] = Heap[next];
		now = next;
		next <<= 1;
		if (next + 1 <= size && Heap[next + 1].cost < Heap[next].cost) ++next;
	}
	Heap[now] = curr;
}

inline void heap_ins(short int node, unsigned int cost){
	Heap[++size].node = node;
	Heap[size].cost = cost;

	heap_elem curr = Heap[size];
	short int now = size, next = now >> 1;

	for (; next && Heap[next].cost > Heap[now].cost; Heap[now] = Heap[next], now = next, next >>= 1);
	Heap[now] = curr;
}

void Dijkstra(char source_idx, int cnt){
	memset(dist, 255, sizeof(int) * (N + 1));
	dist[__K[(int)source_idx]] = 0;
	heap_ins(__K[source_idx], 0);

	while (size){
		heap_elem now = Heap[1];
		heap_pop();

		if (now.cost > dist[now.node]) continue;

		foreach(G[now.node])
			if (it->maxCnt >= cnt && dist[it->node] > now.cost + it->cost * (cnt + 1))
				dist[it->node] = now.cost + it->cost * (cnt + 1),
				heap_ins(it->node, now.cost + it->cost * (cnt + 1));
	}

	for (int i = 1; i <= K; ++i) pr_dist[source_idx][i][cnt] = dist[__K[i]];
}

inline char bitcount(int x){
	char cnt = 0;
	for (; x; ++cnt, x -= x & -x);
	return cnt;
}

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

	K = r_int32(), N = r_int32(), M = r_int32();
	__K[0] = 1;
	for (int i = 1; i <= K; ++i) __K[i] = r_int32(), prisoner[__K[i]] = 1;

	while (M--){
		short int A, B;
		unsigned int cost;
		char cnt;
		A = r_int32(), B = r_int32(), cost = r_int32(), cnt = r_int32();
		if (cnt > K) cnt = K;
		assert(cost >= 0);

		G[A] = G[A]->new_edge(B, cnt, cost);
		G[B] = G[B]->new_edge(A, cnt, cost);
	}

	for (int i = 0; i <= K; ++i)
		memset(pr_dist[i], 255, sizeof (int) * (K + 1) * 16);

	Dijkstra(0, 0);
	for (int i = 1; i <= K; ++i)
		for (int j = 1; j < K; ++j)
			Dijkstra(i, j);

	unsigned int ans = 1 << 31;
	for (int i = 0; i < K; ++i)
		memset(comb[i], 255, sizeof(int) * (1 << K));
	
	for (int i = 1; i < (1 << K); ++i){
		for (int j = 0; j < K; ++j)
			if ((i & (1 << j))){
				int x = i ^ (1 << j);
				char bits = bitcount(i);

				if (!x) comb[j][i] = pr_dist[0][j + 1][0];
				else for (int k = 0; k < K; ++k)
					if (x & (1 << k) && pr_dist[k + 1][j + 1][bits - 1] != INF && comb[k][x] != INF)
						comb[j][i] = MIN(comb[j][i], comb[k][x] + pr_dist[k + 1][j + 1][bits - 1]);

				if ((i == (1 << K) - 1) && comb[j][i] < ans) 
					ans = comb[j][i];
			}
	}

	w_int32(ans);

	return 0;
}