Cod sursa(job #463168)

Utilizator simona.poilincaSimona Poilinca simona.poilinca Data 14 iunie 2010 18:02:43
Problema Gutui Scor 100
Compilator c Status done
Runda teme_upb Marime 6.91 kb
/*
		MARIN VIOLETA
		325 CA
		TEMA 1 - PROBLEMA 2
*/	

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

/*
structura "gut" retine pentru fiecare gutuie nivelul si greutatea;
nivelul este definit in felul urmator: 
	o gutuie care trebuie culeasa la primul pas (altfel se va afla la o inaltime prea mare)
	se afla pe nivelul 1;
	o gutuie care trebuie culeasa la al doilea pas cel tarziu (altfel se va afla la o 
	inaltime prea mare) se afla pe nivelul 2; etc.
gutuile care se afla la inaltimi mai mari decat inaltimea maxima la care poate ajunge Gigel
vor avea nivelul 0;
*/ 
struct gut{
	unsigned int level;	
	unsigned int weight;
	};

/*
vectorul "gutui", format din structuri "gut", va retine toate gutuile "citite" din fisierul de intrare;
*/ 
struct gut *gutui;

/*
functie folosita la sortarea gutuilor;
acestea se sorteaza crescator, in functie de nivel;
daca nivelele mai multor gutui sunt egale, acestea sunt puse in ordinea descrescatoare a greutatilor;
*/  
int compare (const void * a, const void * b)
{
	if ((*(struct gut*)a).level == (*(struct gut*)b).level)	
		return -((*(struct gut*)a).weight - (*(struct gut*)b).weight); 
	 return ((*(struct gut*)a).level - (*(struct gut*)b).level); 	
}

/*
In continuare, 3 functii necesare structurii de min-heap pe care am folosit-o;
functia "parent" returneaza indicele parintelui nodului primit ca argument;
complexiatet: O(1);
*/  
unsigned int parent(unsigned int i){
	if (i % 2 == 0) return (i/2 - 1);
		else return i/2;
}

/*
functia "insert" insereaza pe ultima pozitie nodul cu greutate w si ii gaseste locul in heap;
se fac interschimbari succesive intre nod si parintele sau pana se respecta ordinea din heap;
complexitate: O(log n), unde n este numarul de elemente total al heapului;
complexitatea este aceasta, doarece, in cel mai defavorabil caz, se parcurg  toate nivelele,
pentru a gasi locul potrivit nodului nou inserat, iar heap-ul are [log n] nivele; 
*/
void insert(unsigned int w, unsigned int *heap, unsigned int pos){
heap[pos] = w;
unsigned int aux;
while ((pos > 0) && (heap[pos] < heap[parent(pos)])) {
					aux = heap[parent(pos)];
					heap[parent(pos)] = heap[pos];
					heap[pos] = aux;
					pos = parent(pos);
					}  
}

/*
functia "minheapify" gaseste locul noii radacini a heapului;
nodul curent se compara cu succesorii sai si se interschimba cu minimul dintre acestia; 
complexiate O(log n), unde n = numarul de elemente total al heapului;
in cel mai defavorabil caz, se parcug toate nivelele heapului;
*/ 
void minheapify(unsigned int *heap, unsigned int i, unsigned int length){

unsigned int l = 0, r = 0, least, aux;
if ((2 * i + 1) < length) l = 2 * i + 1;
if ((2 * i + 2) < length) r = 2 * i + 2;
if ((l == 0) || (r == 0)) return;
	else
	if ((l != 0) && (r == 0))
		{
		if (heap[l] < heap[i]) {
					aux = heap[i];
					heap[i] = heap[l];
					heap[l] = aux;
					minheapify(heap, l, length);
					}
				else return;
		}
	 else
		{
		if (heap[l] > heap[r]) least = r;
			else least = l;
		if (heap[i] > heap[least]) {
					  aux = heap[i];
					  heap[i] = heap[least];
					  heap[least] = aux;
					  minheapify(heap, least, length);	
					   }
		else return;	 	
  		}
}


int main(){
	unsigned int i, k, t;
	unsigned int h,u,n;	
	unsigned int level,no_levels, min_level = 0xffffffff;
	unsigned int max = 0;
	
	FILE *f = fopen("gutui.in","r");
	fscanf(f, "%u", &n);
	fscanf(f, "%u", &h);
	fscanf(f, "%u", &u);
	
	gutui = (struct gut *)malloc(n * sizeof(struct gut));
	
	/*
	se citesc datele pentru fiecare gutuie;
	min_level va contine de fapt inaltimea minima dintre inaltimile valide ale tuturor gutuilor citite;
	min_level va fi folosit la calcularea numarului total de pasi;
	*/
	for (i = 0; i < n; i++)
		{
		fscanf(f, "%u", &level);
		fscanf(f, "%u", &gutui[i].weight);
		if (level > h) gutui[i].level = 0;
			else
			{
			gutui[i].level = (h - level)/u + 1 ;
			if (min_level > level) min_level = level;
			}
		}
	fclose(f);

	/*
	se sorteaza gutuile in ordinea specificata in functia "compare";
	Complexitate qsort : O(n * log n);	
	*/
	qsort(gutui, n, sizeof(struct gut), compare);
	
	/*
	se calculeaza numarul total de pasi pe care il va face Gigel;
	in cazul in care nicio inaltime a gutuilor nu a fost valida, numarul de pasi va fi 0;
	*/
	if (min_level != 0xffffffff)
 		no_levels = (h - min_level)/u + 1;
		else 
		no_levels = 0;

	/*
	daca numarul total de pasi este 0, greutatea maxima va fi 0 si programul se incheie;
	*/
	if (no_levels == 0) 	{
			 	f = fopen("gutui.out", "w");
				fprintf(f, "%u\n", max);
				fclose(f);
				return 0; 	
				}
	/*
	heapul nu poate avea mai multe elemente decat numarul total de pasi, adica decat numarul
	total de gutui culese;
	*/
	unsigned int * heap = (unsigned int *)calloc(no_levels,sizeof(unsigned int));
	
	level = 0; k = 0;  t = 0; 	

	/*
	se parcurg toate gutuile (care sunt sortatea in felul descris anterior) si se incearca pentru fiecare gutuie,
	sa se gaseasca un loc in heap;
	heapul va contine la final greutatile gutuilor culese;
	k contorizeaza numarul de gutui de pe un anumit nivel;
	t contorizeaza numarul de gutui introduse in heap la un moment dat;
	level este nivelul curent;
	Complexitate totala : O(n * log n), deoarece se parcurg toate gutuile, o singura data, si pentru fiecare gutuie,
	cea mai costisitoare operatie care poate fi efectuala este apelul functiei "insert" sau a functiei "minheapify",
	iar aceste functii au complexitatea O(log n);
	*/ 
	for (i = 0; i < n; i++){
		if (gutui[i].level > level) {
						/*
						am gasit un nou nivel;
						k = 1; este sigur o gutuie pe acest nivel;
						pasul curent se acutalizeaza;  
						*/
						level = gutui[i].level;
						k = 1;
					   }
						else
						
						k = k + 1;
		/*
		nivelul curent este egal cu nivelul gutuii anterioare;
		contorizam gutuile de pe acest nivel;
		daca sunt mai multe gutui pe acest nivel decat cate pot fi culese,
		ele nu ne mai intereseaza;
		*/  
		if ((gutui[i].level != 0)&&(k <= gutui[i].level)){
						/* 	
						daca numarul de gutui din heap este mai mic decat pasul curent,
						gutuia poate fi culeasa fara probleme;
						o inseram in heap si actualizam greutatea totala "max", dar si 
						numarul total de gutui culese;
						*/  
						if (t < level) {
								t = t + 1;
								insert(gutui[i].weight, heap, t - 1);
								max = max + gutui[i].weight; 
								   }
							else
							/* 
							numarul de gutui din heap este mai mare sau egal cu pasul curent;
							gutuia nu va fi culeasa decat daca greutatea sa este mai mare
							decat minimul greutatilor gutuilor culese;
							*/ 	
							  {
							if (heap[0] < gutui[i].weight) {
											/*
											se actualizeaza greutatea totala "max"
											si se pastreaza relatia de ordine in heap;
											*/
											max = max - heap[0] + gutui[i].weight;	
											heap[0] = gutui[i].weight;
											minheapify(heap, 0, level);
											}
							  }
						}
					
		}	 
								    
						
	
	f = fopen("gutui.out", "w");
	fprintf(f, "%u\n", max);
	fclose(f);

	free(gutui);
	free(heap);
	
return 0;
}