Cod sursa(job #438532)

Utilizator valentin.gosuGosu Valentin valentin.gosu Data 10 aprilie 2010 20:57:16
Problema Gutui Scor 100
Compilator c Status done
Runda teme_upb Marime 6.9 kb
/**
 *
 * Nume: Valentin GOSU
 * Grupa: 322CA 
 * Email: [email protected]
 * 
 */

 
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

typedef void *T;

/* Structura heap-ului */ 
struct heap_s {
    int size;
    int capacity;
    T *data;
};

typedef struct heap_s *Heap;

/*
 * Functia H_New creaza un heap nou cu capacitatea 'max'
 *  aloca memorie pentru el, si returneaza adresa lui
 */
Heap H_New(int max)
{
    Heap heap;
    assert(max > 0);
    heap = (struct heap_s *) malloc(sizeof(struct heap_s));
    heap->size = 0;
    heap->capacity = max;
    heap->data = (T*)malloc((heap->capacity) * sizeof(T));
    return heap;
}

/*
 * Functia elibereaza memoria folosita de heap.
 */
void H_Delete(Heap heap)
{
    assert(heap);
    heap->capacity = 0;
    heap->size = 0;
    if (heap->data) /* este posibil ca vectorul sa nu fie alocat */
        free(heap->data); 
    free(heap);
}

/* Returneaza 1 daca heapul este gol si 0 daca contine elemente */
int H_Empty(Heap heap)
{
    assert(heap);
    return heap->size == 0;
}

/* Returneaza 1 daca heapul a atins capacitatea maxima */
int H_Full(Heap heap)
{
    assert(heap);
    return heap->size == heap->capacity;
}

/* Returneaza primul element din heap */
T H_FindMin(Heap heap)
{
    assert(heap);
    assert(heap->size > 0);
    return heap->data[0];
}

static void H_Down(Heap h, int p, int (*compare) (T x, T y));
static void H_Up(Heap h, int p, int (*compare) (T x, T y));

/* Sterge primul element din heap si actualizeaza heapul */
void H_RemoveMin(Heap heap, int compare(T x, T y))
{
    T x;
    assert(heap);
    assert(heap->size > 0);
    assert(compare);
    x = heap->data[0];
    heap->data[0] = heap->data[--heap->size];
    H_Down(heap, 0, compare);
}

/* Insereaza un element in heap */
void H_Insert(Heap * heap, T key, int compare(T x, T y))
{
    int i, capacity;
    assert(heap);
    assert(*heap);
    assert((*heap)->size >= 0);
    if ((*heap)->size == (*heap)->capacity) {

        T *data;
        capacity = (*heap)->capacity;
        data = (*heap)->data;
        (*heap)->data = NULL;
        H_Delete(*heap);
        *heap = H_New(capacity*2);
        (*heap)->size = capacity;
        for (i = 0; i < (*heap)->size; i++)
            (*heap)->data[i] = data[i];
        assert(data);
        free(data);

    }
    (*heap)->data[(*heap)->size++] = key;
    H_Up(*heap, (*heap)->size - 1, compare);
}

/* Returneaza numarul de elemente din heap */
int H_Size(Heap heap)
{
    assert(heap);
    return heap->size;
}

/* Returneaza capacitatea heapului */
int H_Capacity(Heap heap)
{
    assert(heap);
    return heap->capacity;
}

/* Functia Coboara elementul din pozitia p si actualizeaza heapul */
static void H_Down(Heap h, int p, int (*compare) (T x, T y))
{
    int fiu;
    T t;
    while (2 * p + 1 < h->size) {
        fiu = 2 * p + 1;
        if (fiu + 1 < h->size && compare(h->data[fiu], h->data[fiu
                                                               + 1]) > 0) {
            fiu++;
        }
        if (compare(h->data[fiu], h->data[p]) < 0) {
            t = h->data[p];
            h->data[p] = h->data[fiu];
            h->data[fiu] = t;
            p = fiu;
        } else {
            break;
        }
    }
}

/* Functia Urca elementul din pozitia p si actualizeaza heapul */
static void H_Up(Heap h, int p, int (*compare) (T x, T y))
{
    T aux;

    if (p == 0)
        return;

    while (p > 0
           && (compare(h->data[p], h->data[(p - 1) / 2]) <
               0)) {
        aux = h->data[p];
        h->data[p] = h->data[(p - 1) / 2];
        h->data[(p - 1) / 2] = aux;

        p = (p - 1) / 2;
    }
}


 int N,H,U; 
 
 /* Structura ce memoreaza inaltimea si greutatea unei gutui */
 typedef struct {
 	int h;
 	int g;
 	} gutuie;
 

void merge(int, int, int, gutuie*);
void msort(int, int, gutuie*);
void mergesort(int n, gutuie *x){ msort(0, n-1, x); }

void msort(int i, int j, gutuie *x){
   if(i<j){
      int k=(i+j)/2;
      msort(i, k, x);
      msort(k+1, j, x);
      merge(i, k+1, j, x);
   }
}
void merge(int p, int q, int r, gutuie *x){
   int i=p, j=q, k=0;
   gutuie *y = (gutuie*)malloc((r-p+1)*sizeof(gutuie));
   while(i<q && j<=r)
	  /* Se sorteaza elementele dupa nivelul pe care se afla (H-v[i].h)/U
	     iar pe fiecare nivel gutuile sunt sortate dupa descrescator dupa greutate */
      if((H-x[i].h)/U < (H-x[j].h)/U  || ((H-x[i].h)/U == (H-x[j].h)/U && x[i].g>x[j].g ))
         y[k++] = x[i++];
      else
         y[k++] =x[j++];
   while(i < q)
      y[k++] = x[i++];
   while(j <= r)
      y[k++] = x[j++] ;
   for(i=p; i<=r; i++)
      x[i] = y[i-p];
   free(y);
}

 /* Functia de comparatie */
 int comp(T a, T b) {
 	return *(int*)a - *(int*)b;
 	}
 
 
 int main() {
 	FILE * f;
 	FILE * g;
 	f=fopen( "gutui.in","r"); /* Fisierul de intrare */
 	g=fopen("gutui.out","w"); /* Fisierul de iesire */
	
	/* Se citesc valorile N, H si U din fisier */
 	fscanf(f,"%d %d %d",&N,&H,&U);
 	int i;
 	gutuie v[N]; /* Vectorul de valori */
 	
	/* Se citesc valorile din fisier */
	for (i=0;i<N;i++) {
 		int a,b;
 		fscanf(f,"%d %d",&a,&b);
		/* Se ignora gutuile ce depasesc valoarea H */
 		if (a<=H) {
 			v[i].h=a;
 			v[i].g=b;
 		} else {
 			N--;
 			i--;
 			continue;
 			}
 		}
 	
 	/* Se sorteaza elementele dupa nivelul pe care se afla (H-v[i].h)/U
	iar pe fiecare nivel gutuile sunt sortate dupa descrescator dupa greutate */
    mergesort(N,v);
 	
	/* Se foloseste un heap, de dimensiune maxima N, pentru a sorta
	   gutuile culese dupa greutate */
 	Heap heap = H_New(N);
 	
	/* niv reprezinta nivelul curent in cadrul parcurgerii,
	   iar count reprezinta numarul de gutui care mai trebuie culese
	   de pe nivelul respectiv */
 	int niv=(H-v[0].h)/U; 
	int count=niv; /* De pe fiecare nivel se culeg maxim niv gutui */
	
 	for (i=0;i<N;i++) 
 		if ( (H-v[i].h)/U == niv ) {
			/* Se introduc elemente in heap */
 			if ( H_Size(heap) < niv+1 ) {
 				H_Insert(&heap,&v[i].g,comp);
 				count--;
 				continue;
 				}
			/* Daca heapul a atins dimensiunea maxima pentru nivelul respectiv
			   atunci se verifica elementul cu cea mai mica greutate din heap.
			   Daca elementul din heap este mai mic, este inlocuit de v[i].g */
 			if ( H_Size(heap)==niv+1 && count>=0)
 				if (*(int*)H_FindMin(heap)<v[i].g) {
 					H_RemoveMin(heap,comp);
 					H_Insert(&heap,&v[i].g,comp);
 					count--;
 					continue;
 					}
			/* Daca nu mai pot fi culese gutui de pe nivelul respectiv, 
			   se incrementeaza niv */
 			if (count<0) {
 				niv++;
 				count=niv;
 				}
 			} else if ( (H-v[i].h)/U > niv ) {
				/* Daca nivelul elementului curent este mai mare decat 'niv',
				   'niv' este actualizat, si se verifica din nou v[i] */
 				niv = (H-v[i].h)/U;
 				count=niv;
 				i--;
 				continue;
 				}
	
	/* Se extrag elemente din heap si se adauga la suma */
 	int suma=0;			 				
 	while ( H_Size(heap)>0) {
 		suma+=*((int*)H_FindMin(heap));
 		H_RemoveMin(heap,comp);
 		}
	/* Se scrie suma in fisier */
 	fprintf(g,"%d\n",suma);
 	fclose(g);
 	return 0;
 	}