Cod sursa(job #298642)

Utilizator savimSerban Andrei Stan savim Data 6 aprilie 2009 11:46:39
Problema Team Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.73 kb
#include <stdio.h>
#include <vector>
#include <string.h>

using namespace std;

#define MAX_N 512
#define MAX_P 64
#define INF 2147000000

int n, m, p, k, sol;
int stop[MAX_P];
vector <int> A[MAX_N], C[MAX_N];
int D[MAX_N][MAX_N];
int c[MAX_P][MAX_P][MAX_N];

struct heap {
	int nod;
	int cost;
} h[MAX_N * 2], aux;
int pheap[MAX_N], use[MAX_N];

void cit() {
	freopen("team.in", "r", stdin);
	freopen("team.out", "w", stdout);
	
	scanf("%d", &p);
	scanf("%d", &n);
	scanf("%d", &m);
	for (int i = 1; i <= m; i++) {
		int p, q, c;
		scanf("%d %d %d", &p, &q, &c);
		A[p].push_back(q); C[p].push_back(c);
		A[q].push_back(p); C[q].push_back(c);
	}
	for (int i = 1; i <= p; i++)
		scanf("%d ", &stop[i]);
}

void heap_update(int poz) {
	int gas = 0;
	//incerc sa ma duc in jos
	while (poz > 1 && h[poz / 2].cost > h[poz].cost) {
		aux = h[poz / 2]; h[poz / 2] = h[poz]; h[poz] = aux;
		pheap[h[poz / 2].nod] = poz / 2;
		pheap[h[poz].nod] = poz;
		
		gas = 1; poz /= 2;
	}
	
	if (!gas) {
		//incerc sa ma duc in sus in heap
		while ((h[poz * 2].cost < h[poz].cost && poz * 2 <= k) ||
			   (h[poz * 2 + 1].cost < h[poz].cost && poz * 2 + 1<= k)) {
					int next = poz * 2;
					if (poz * 2 + 1 <= k && h[poz * 2 + 1].cost < h[poz * 2].cost)
						next = poz * 2 + 1;
					
					aux = h[poz]; h[poz] = h[next]; h[next] = aux;
					pheap[h[poz].nod] = poz; pheap[h[next].nod] = next;
					
					poz = next;
			   }
	}
}

void dijkstra() {
	//aflu distanta de la toate punctele de oprire la orice punct din graf cu algoritmul
	//lui dijkstra
	
	for (int i = 1; i <= p; i++)
		for (int j = 1; j <= n; j++)
			D[i][j] = INF;
	
	for (int i = 1; i <= p; i++) {
		//lucrez pentru punctul stop[i]
		D[i][stop[i]] = 0;
		
		memset(use, 0, sizeof(use));
		memset(pheap, 0, sizeof(pheap));
		memset(use, 0, sizeof(use));
		
		k = 1; 
		h[1].nod = stop[i]; h[1].cost = 0;
		pheap[stop[i]] = 1;
		
		while (k) {
			int len = A[h[1].nod].size();
			
			for (int j = 0; j < len; j++) {
				int NewNod = A[h[1].nod][j];
				int CNew = h[1].cost + C[h[1].nod][j];
				
				if (use[NewNod] == 0) {
					if (pheap[NewNod] == 0) {
						h[++k].nod = NewNod;
						h[k].cost = CNew;
						pheap[NewNod] = k;
						heap_update(k);
					}
					else {
						int poz = pheap[NewNod];
						if (h[poz].cost > CNew) {
							h[poz].cost= CNew;
							heap_update(poz);
						}
					}
				}
			}
			
			use[h[1].nod] = 1; 
			D[stop[i]][h[1].nod] = D[h[1].nod][stop[i]] = h[1].cost;
			
			//scot primul element din heap
			pheap[h[1].nod] = 0;
			h[1] = h[k]; 
			pheap[h[k].nod] = 1;
			h[k].nod = h[k].cost = 0;
			k--;
			
			heap_update(1);
		}
	}
}

void dinamica() {
	//am aflat distanta intre oricare stop[i] si orice alt nod, in D[i][nod]
	//c[d][i][k] = costul minim pentru a duce persoanele de pe pozitiile
	//             i...i + d acasa, ele fiind in acest moment in nodul stop[k]

	for (int d = 0; d < p; d++)
		for (int i = 1; i + d <= p; i++)
			for (int k = 1; k <= p; k++)
				c[d][i][stop[k]] = INF;
	
	sol = INF;
	for (int d = 0; d < p; d++)
		for (int i = 1; i + d <= p; i++)
			for (int k = 1; k <= p; k++) {
				
				for (int t = 0; t <= d; t++) {
					//persoana de pe pozitia i + t se va desparti de grup
					int val = D[stop[k]][stop[i + t]];
					if (t - 1 >= 0) val += c[t - 1][i][stop[i + t]];
					if (d - t - 1 >= 0) val += c[d - t - 1][i + t + 1][stop[i + t]];
					
					if (c[d][i][stop[k]] > val)
						c[d][i][stop[k]] = val;
				}
				
				if (d == p - 1)
					if (c[d][i][stop[k]] + D[1][stop[k]] < sol)
						sol = c[d][i][stop[k]] + D[1][stop[k]];
			}
	printf("%d\n", sol);
}

int main() {

	cit();
	dijkstra();
	dinamica();

	return 0;
}