Cod sursa(job #463172)

Utilizator simona.poilincaSimona Poilinca simona.poilinca Data 14 iunie 2010 18:07:17
Problema Gutui Scor 100
Compilator c Status done
Runda teme_upb Marime 4.32 kb
/* Nume: Mirica Emma-Camelia
 * Grupa: 322CA
 * E-mail: [email protected]
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct H {
    int *val; // vectorul de valori din heap
    int dim; // dimensiunea heap-ului
} Heap;

 // functie de interschimbare a doua valori dintr-un vector
void swap(int a[], int i, int j)
{
    int aux;
    aux = a[i];
    a[i] = a[j];
    a[j] = aux;
}
 // creeaza un heap care poate avea dimensiunea maxima n si dimensiunea initiala este dimHeap
Heap *CreateHeap(int n, int dimHeap)
{
    Heap *h = (Heap *) malloc(sizeof(Heap));
    h->dim = dimHeap;
    h->val = (int *) malloc(n * sizeof(int));
    return h;
}

void ElibereazaHeap(Heap * h)
{
    free(h->val);
    free(h);
}

int Parinte(Heap * h, int poz)
{
    if ((poz - 1) / 2 < h->dim)
        return (poz - 1) / 2;
    else
        return -1;
}

int DescS(Heap * h, int poz)
{
    if (2 * poz + 1 < h->dim)
        return 2 * poz + 1;
    else
        return -1;
}

int DescD(Heap * h, int poz)
{
    if (2 * poz + 2 < h->dim)
        return 2 * poz + 2;
    else
        return -1;
}

void UrcaValoare(Heap * h, int poz)
{
    if (poz == 0)
        return;
    while (poz > 0 && h->val[poz] < h->val[Parinte(h, poz)]) {
        swap(h->val, poz, Parinte(h, poz));
        poz = Parinte(h, poz);
    }
}

void CoboaraValoare(Heap * h, int poz)
{
    int w = 2 * poz + 1;
    while (w < h->dim) {
        if (w + 1 < h->dim)
            if (h->val[w + 1] < h->val[w])
                w++;

        if (h->val[poz] < h->val[w])
            return;

        swap(h->val, poz, w);
        poz = w;
        w = 2 * poz + 1;
    }
}

void AdaugaValoare(Heap * h, int val)
{
    h->dim++;
    h->val[h->dim - 1] = val;
    UrcaValoare(h, h->dim - 1);
}

int ExtrageMinim(Heap * h)
{
    int min = h->val[0];
    h->val[0] = h->val[h->dim - 1];
    h->dim--;
    CoboaraValoare(h, 0);
    return min;
}

int Minim(Heap * h)
{
    return h->val[0];
}

// pentru sortare in O(n*log(n))
void merge(int *h, int *w, int p, int q, int r, int H, int U)
{
    int i = p;
    int j = q + 1;

    int *tmp = (int *) malloc((r - p + 1) * sizeof(int));
    int *tmp2 = (int *) malloc((r - p + 1) * sizeof(int));
    int k = 0;

    while ((i <= q) && (j <= r)) {
        if (((H - h[i]) / U < (H - h[j]) / U)
            || ((H - h[i]) / U == (H - h[j]) / U && (w[i] > w[j]))) {
            tmp2[k] = w[i];
            tmp[k++] = h[i++];
        } else {
            tmp2[k] = w[j];
            tmp[k++] = h[j++];
        }
    }

    while (i <= q) {
        tmp2[k] = w[i];
        tmp[k++] = h[i++];
    }

    while (j <= r) {
        tmp2[k] = w[j];
        tmp[k++] = h[j++];
    }

    memcpy(h + p, tmp, (r - p + 1) * sizeof(int));
    memcpy(w + p, tmp2, (r - p + 1) * sizeof(int));
    free(tmp);
    free(tmp2);
}

void mergeSort(int *h, int *w, int p, int r, int H, int U)
{
    if (p < r) {
        int q = (p + r) / 2;
        mergeSort(h, w, p, q, H, U);
        mergeSort(h, w, q + 1, r, H, U);
        merge(h, w, p, q, r, H, U);
    }
}


int main()
{
    int N, H, U;
    FILE *f, *g;
    f = fopen("gutui.in", "r");
    g = fopen("gutui.out", "w");
    fscanf(f, "%d%d%d", &N, &H, &U);
    int h[N], w[N], hh, ww;
    int i;
    int n = 0;

    // adaugam doar gutuile care initial se afla la o inaltime mai mica sau egala cu H
    for (i = 0; i < N; i++) {
        fscanf(f, "%d %d\n", &hh, &ww);
        if (hh <= H) {
            w[n] = ww;
            h[n++] = hh;
        }
    }

    // sortam in O(n*log(n)) crescator dupa nivel si apoi pentru niveluri egale descrescator dupa greutati   
    mergeSort(h, w, 0, n - 1, H, U);
    Heap *aux;
    aux = CreateHeap(n, 0);
    int nivel;
    
    // alegerea optima a gutuilor pentru a fi alese in O(n*log(n))
    for (i = 0; i < n; i++) {
        nivel = (H - h[i]) / U;
        if (aux->dim < nivel + 1)
            AdaugaValoare(aux, w[i]);
        else {
            if (Minim(aux) < w[i]) {
                ExtrageMinim(aux);
                AdaugaValoare(aux, w[i]);
            }
        }
    }
    // in heap se vor afla gutuile care vor fi culese in mod optim si atunci greutatea lor va fi suma elementelor din heap
    int Gmax = 0;
    for (i = 0; i < aux->dim; i++)
        Gmax += aux->val[i];
    fprintf(g, "%d\n", Gmax);
    // dezalocarea structurii de heap
    ElibereazaHeap(aux);
    fclose(f);
    fclose(g);
    return 0;
}