/* 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;
}