Cod sursa(job #463121)

Utilizator simona.poilincaSimona Poilinca simona.poilinca Data 14 iunie 2010 17:02:30
Problema Gutui Scor 100
Compilator c Status done
Runda teme_upb Marime 7.52 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;
}