Cod sursa(job #462887)

Utilizator plastikDan George Filimon plastik Data 13 iunie 2010 23:50:25
Problema Arbore partial de cost minim Scor 0
Compilator c Status done
Runda Arhiva educationala Marime 2.87 kb
// http://infoarena.ro/problema/apm

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

#define INF INT_MAX
#define NMAX 200010

int Heap[NMAX], Pos[NMAX], Cost[NMAX];
int hsz = 0;

inline int cmp(int a, int b) { // a = parintele lui b
	return (Cost[a] < Cost[b]);
}
inline void swap(int *a, int *b) {
	int c = *a;
	*a = *b;
	*b = c;
}

void swim(int p) { // bubble-up
	while (p / 2 >= 1 && !cmp(Heap[p / 2], Heap[p])) {
		swap(&Heap[p], &Heap[p / 2]);
		swap(&Pos[Heap[p]], &Pos[Heap[p / 2]]);
		p /= 2;
	}
	Pos[Heap[p]] = p;
}

void sink(int p) { // bubble-down
	int j;
	while (2 * p <= hsz) {
		j =  2 * p;
		if (j + 1 <= hsz && !cmp(Heap[j], Heap[j + 1]))
			++ j;
		if (!cmp(Heap[p], Heap[j])) {
			swap(&Heap[p], &Heap[j]);
			swap(&Pos[Heap[p]], &Pos[Heap[j]]);
			p = j;
		} else
			break;
	}
}

void heapInsert(int i) {
	Heap[++ hsz] = i;
	Pos[i] = hsz;
	swim(hsz);
}

int heapPop() {
	int temp = Heap[1];
	Pos[Heap[hsz]] = 1;
	swap(&Heap[hsz], &Heap[1]);
	-- hsz;
	sink(1);
	return temp;
}

void heapChangePriority(int newPriority, int p) {
	int shouldSink = newPriority > Cost[Heap[p]]; // !cmp == true
	Cost[Heap[p]] = newPriority;
	if (shouldSink)
		sink(p);
	else
		swim(p);
}

typedef struct {
	int b, cost;
} pair;

pair **Next; // vecinii fiecarui nod
int *numNext, // numarul de vecini ai fiecarui nod
    n, m; // numarul de noduri / muchii
inline void nodeAdd(int a, int b, int cost) {
	Next[a] = (pair*)realloc(Next[a], (numNext[a] + 1) * sizeof(pair));
	pair newPair; newPair.b = b, newPair.cost = cost;
	Next[a][numNext[a] ++ ] = newPair;
}

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

	scanf("%d%d", &n, &m);
	Next = (pair**)calloc(n, sizeof(pair*));
	numNext = (int*)calloc(n, sizeof(int));
	int *Used = (int*)calloc(n, sizeof(int)),
	    *Pred = (int*)calloc(n, sizeof(int));

	int i, a, b, c;
	for (i = 0; i < m; ++ i) {
		scanf("%d%d%d", &a, &b, &c);
		nodeAdd(a - 1, b - 1, c);
		nodeAdd(b - 1, a - 1, c);
	}
	
	// ** algoritmul lui Prim
	
	// 1. introduc fiecare nod in heap
	Cost[0] = 0;
	heapInsert(0); // aleg sa pornesc din primul nod
	for (i = 1; i < n; ++ i) {
		Cost[i] =  INF;
		Used[i] = 0;
		heapInsert(i);
	}

	int u;
	pair next;
	// 2. ciclul principal
	while (hsz > 0) {
		/*for (i = 1; i <= hsz; ++ i)
			fprintf(stderr, "%d ", Cost[Heap[i]]);
		fprintf(stderr, "\n");*/

		u = heapPop();
			Used[u] = 1;
		for (i = 0; i < numNext[u]; ++ i) {
			next = Next[u][i];
			if (!Used[next.b] && Cost[next.b] > next.cost) {
				Cost[next.b] = next.cost;
				heapChangePriority(Cost[next.b], Pos[next.b]);
				Pred[next.b] = u;
			}
		}
	}
	int cost;
	for (i = 1; i < n; ++ i)
		cost += Cost[i];

	// 3. afisare
	printf("%d\n%d\n", cost, n - 1);
	for (i = 1; i < n; ++ i)
		printf("%d %d\n", i + 1, Pred[i] + 1);
	// **

	for (i = 0; i < n; ++ i)
		free(Next[i]);
	free(Next);
	free(numNext);
	free(Pred);
	free(Used);
	return 0;
}