Cod sursa(job #440092)

Utilizator ralu_k_sSocea Raluca ralu_k_s Data 11 aprilie 2010 21:52:06
Problema Gutui Scor 10
Compilator c Status done
Runda teme_upb Marime 4.77 kb
/* SOCEA Raluca, 324 CB, PA - Tema 1 */

// Problema 2: Gutui

#include<stdio.h>
#include<stdlib.h>
unsigned long int *h, *g;

int compare (const void * a, const void * b)  // Functia compare foloseste criteriul de comparare 
{
	int i = *(int*)a, j = *(int *)b;	// descrescator dupa greutate
	if( *(g+i) < *(g+j) )
		return 1;
	if( *(g+i) == *(g+j) )			// si apoi dupa inaltimea la care se afla gutuia.
	{	if( *(h+i) < *(h+j) )
			return 1;
		if( *(h+i) == *(h+j) )		// Utilizare: qsort
			return 0;
	}
	return -1;	
	
}


int main()
{	
	unsigned long int H, U, Gmax=0, gcrt, hcrt;
	int N;

	// Citire
	FILE *fin;			// deschidere fisier intrare
	fin = fopen("gutui.in","rt");
	fscanf(fin,"%i %lu %lu",&N, &H, &U);	
	
	// Alocare vectori de dimensiune N (greutatile si inaltimile gutuielor)	
	g = (unsigned long int *) calloc(N, sizeof(unsigned long int));
	h = (unsigned long int *) calloc(N, sizeof(unsigned long int));

	int *ord = (int *) calloc(N, sizeof(int)); // Vectorul ord retine indici de la 0->n-1; Initial ord[i] = i;
						// dupa sortare ord[i] = k are semnificatia:  in vectorul ordonat dupa criteriul din functia compare, 
	int i,j;				// pe pozitia i se afla elementul cu indicele k din lista initiala.
	for(i=0;i<N;i++)
	{	fscanf(fin,"%lu %lu",h+i, g+i);	// citirea inaltimii si greutatii pentru fiecare gutuie
		*(ord+i) = i;			// initializare vector ord
	}
	
	fclose(fin);  	// inchidere fisier intrare

	qsort(ord, N, sizeof(int), compare);	//sortare in ordine descrescatoare dupa greutate si dupa inaltime 
						//( se va modifica ordinea indicilor din vectorul ord, vectorii g si h raman neschimbati) 
/*	for(i=0;i<N;i++)
		printf("%i ", *(ord+i)+1 );
	printf("\n");
*/
	int *v = (int *) calloc(N, sizeof(int)); // Vectorul v[i] retine cu cati pasi s-a cules gutuia i inainte de a se ridica creanga prea sus
	for(i=0;i<N;i++)			 // pentru ca Gigel sa nu o mai poata ajunge ( Daca H = 100 si U = 10, iar h[i] = 75, iar gutuia i e
		*(v+i) = -1;			// prima culeasa, v[i] = 2. Daca se mai culegeau 2 gutui inainte, gutuia i s-ar fi aflat la h = 95.
						// Daca a 3-a gutuie aleasa nu ar fi fost gutuia i, Gigel n-ar mai fi putut sa o ajunga ). 
/*	for(i=0;i<N;i++)			
		printf("%i ", *(v+i) );
	printf("\n");
*/
	int  stop = -1;
	unsigned long int niv = 0;
	for(i=0; i<N;i++)		//Luam pe rand toate gutuile descrescator dupa greutate si, apoi, inaltime. 
	{	gcrt = *(g+ *(ord+i));	// greutatea de pe pozitia i in multimea sortata
		hcrt = *(h+ *(ord+i));  // inaltimea de pe pozitia i in multimea sortata
		if(hcrt > H)
			*(v+i) = -2;	// daca inaltimea curenta depaseste inaltimea maxima, v[i] = -2.
		else
			if( H < niv*U + hcrt)  // daca dupa cele niv gutui deja culese, gutuia i nu poate fi ajunsa
			{		
				if(stop == -1)		// v[i] ramane -1.
					stop = i;	// stop pastreaza pozitia primei gutui care n-a fost culeasa, in multimea sortata
				else continue;
			}
			else
			{//	printf("niv: %i  H-niv*U: %lu  hcrt: %i   v[i]: %i", niv, H-niv*U,hcrt, *(v+i));  
				*(v+i) = (H-niv*U -hcrt)/U; 		// Daca gutuia poate fi culeasa, se actualizeaza v[i].
			//	printf("-> v[i] modificat: %i \n", *(v+i));
				Gmax += gcrt;
				niv++;	
			}
		
	}

	// Pana aici, am folosit un algoritm Greedy. Sorteaza gutuile si le selecteaza pe cele cu greutatea mai mare, cat timp ajunge la ele.

	// In continuare, cautam printre gutuile ramase sa vedem daca ar fi putut fi culese intr-un pas intermediar.

	for(i=0;i<N;i++)
		printf("%i ", *(v+i) );
	printf("\n%lu\n", Gmax);
//	printf("\nniv: %i\n", niv);
//	printf("\nstop: %i\n", stop);
	int min, k , re, gasit;
	
	for(i=stop; i< N; i++)
	{	
		while(*(v+i)!= -1 && i<N)		// Daca v[i] = -1, analizam cazul gutuii curente.
			i++;
		if(i==N)
			break;

		hcrt = *(h+ *(ord+i));		 // inaltimea gutuii curente
		min = 	N;	
		j = N-1;	
		re = niv;	// retine indicele gutuii(in ordinea culegerii) dupa care incercam intercalarea culegerii gutuii de pe pozitia i.
		gasit = 1;
		while( *(v+j)!=0 && H < re*U + hcrt && j>=0)
		{				// Parcurgem vectorul v de la coada utilizand contorul j. 
			if( *(v+j)>0)		// Daca inainte de j mai putem lua o gutuie (crengile nu se ridica a.i. sa afecteze gutuile deja culese)
			{	re--;		// adica v[j] > 0, atunci 
				*(v+j) = *(v+j) - 1;
				if(*(v+j) < min)	// actualizam v[j]
					min = *(v+j); 
			}
			
			j--;
			if(*(v+j)==0)
				gasit=0;	
		}
		
				
		if( gasit )			// Daca am gasit o solutie de a culege si gutuia i, actualizam greutatea totala (Gmax)
		{	
			Gmax += *(g+ *(ord+i)); // v[i] si numarul de gutui culese (niv) 
			*(v+i) = min;
			niv++;
		}
		else
		for(k = j+1; k<N;k++)
				if(*(v+k)>=0)
					(*(v+k))++;
		
	}

	for(i=0;i<N;i++)
		printf("%i ", *(v+i) );	
		
	
	//Afisare
	FILE *fout;
	fout = fopen("gutui.out","wt"); // deschidere fisier scriere
	fprintf(fout,"%lu", Gmax);	
	printf("\n%lu\n", Gmax);
	fclose(fout);			// inchidere fisier output
	return 0;
}