Cod sursa(job #439866)

Utilizator skeletAndrei Casian skelet Data 11 aprilie 2010 20:03:33
Problema Gutui Scor 10
Compilator c Status done
Runda teme_upb Marime 4.22 kb
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

#define INFILE  "gutui.in"
#define OUTFILE "gutui.out"

/* #define DEBUG */

#define SCRIE_EROARE(eroare) fprintf( stderr, "Eroare in %s: %s\n", __func__, eroare );

/* Structura de gutuie */
typedef struct
{
    int i_imax;
    int i_greutate;
} gutuie_t;

/* Vrem sa sortam crescator dupa i_imax si descrescator dupa i_greutate */
int gutuie_compara( gutuie_t *una, gutuie_t *alta )
{
    if( una->i_imax < alta->i_imax )
        return -1;
    if( una->i_imax > alta->i_imax )
        return +1;
    if( una->i_greutate > alta->i_greutate )
        return -1;
    if( una->i_greutate < alta->i_greutate )
        return +1;
    return 0;
}

gutuie_t *gutui_merge( int i_n1, gutuie_t *p_gutui1, int i_n2, gutuie_t *p_gutui2 )
{
    gutuie_t *p_gutui3 = calloc( i_n1 + i_n2, sizeof(gutuie_t) );
    int i1, i2, i;

    for( i = i1 = i2 = 0; i1 < i_n1 && i2 < i_n2; ++ i )
        p_gutui3[i] = gutuie_compara( p_gutui1 + i1, p_gutui2 + i2 ) < 0 ? p_gutui1[i1 ++] : p_gutui2[i2 ++];

    while( i1 < i_n1 )
        p_gutui3[i ++] = p_gutui1[i1 ++];
    while( i2 < i_n2 )
        p_gutui3[i ++] = p_gutui2[i2 ++];

    if( i != i_n1 + i_n2 )
        SCRIE_EROARE( "wtf, intorc mai putine elemente decat trebuie" )

    return p_gutui3;
}

void gutui_merge_sort( int i_ngutui, gutuie_t *p_gutui )
{
    if( i_ngutui <= 1 )
        return;

    int i_n1 = i_ngutui / 2;
    int i_n2 = i_ngutui - i_n1;
    gutuie_t *p_jumate1 = p_gutui;
    gutuie_t *p_jumate2 = p_gutui + i_n1;

    gutui_merge_sort( i_n1, p_jumate1 );
    gutui_merge_sort( i_n2, p_jumate2 );

    gutuie_t *p_sortate = gutui_merge( i_n1, p_jumate1, i_n2, p_jumate2 );
    memcpy( p_gutui, p_sortate, i_ngutui * sizeof(gutuie_t) );
    free( p_sortate );
}

#ifdef DEBUG
void gutui_afiseaza( int i_n, gutuie_t *p_gutui )
{
    int i;
    for( i = 0; i < i_n; ++ i )
        printf( "(%d, %d); ", p_gutui[i].i_imax, p_gutui[i].i_greutate );
    printf( "\n" );
}
#endif

int gutui_aduna_greutati( int i_n, gutuie_t *p_gutui )
{
    int s = 0;
    gutuie_t *p_last = p_gutui + i_n;
    while( p_gutui < p_last )
        s += (*(p_gutui ++)).i_greutate;

    return s;
}

int gutui_calculeaza_greutate_maxima( int i_n, gutuie_t *p_gutui )
{
    if( i_n <= 0 )
        return 0;

    int i_last_imax = p_gutui->i_imax;
    int i_luat = 0, i_best = 0;
    int i_disponibile;
    int i;
    int s = 0;
    gutuie_t *p_best = p_gutui;

    for( i = 0; i < i_n; ++ i )
    {
        i_disponibile = p_gutui[i].i_imax - i_last_imax;
        if( i_disponibile > i - i_best )
            i_disponibile = i - i_best;
        if( i_disponibile > 0 )
        {
            s += gutui_aduna_greutati( i_disponibile, p_best );
            p_best = p_gutui + i;
            i_best = i;
            i_luat += i_disponibile;
        }

        #ifdef DEBUG
        printf( "%d -> %d disponibile, %d luat, %d suma\n", i, i_disponibile, i_luat, s );
        #endif
    }

    s += gutui_aduna_greutati( i_luat - p_best->i_imax + 1, p_best );
    #ifdef DEBUG
    printf( "%d -> %d suma\n", i, s );
    #endif

    return s;
}

int main( int argc, char *argv[] )
{
    int i_n = 0, i_h = 0, i_u = 0;

    /* Citeste datele de intrare */
    FILE *fin = fopen( INFILE, "r" );
    if( !fin )
    {
        SCRIE_EROARE( "Nu pot deschide fisierul de intrare!" )
        return 2;
    }

    fscanf( fin, "%d %d %d\n", &i_n, &i_h, &i_u );
    gutuie_t *p_gutui = calloc( i_n, sizeof(gutuie_t) );

    if( i_u == 0 )
        SCRIE_EROARE( "Inaltimea la care se ridica gutuile este 0!" )

    int i, i_inaltime;
    for( i = 0; i < i_n; ++ i )
    {
        /* Pune o gutuie in lista */
        fscanf( fin, "%d %d", &i_inaltime, &p_gutui[i].i_greutate );
        p_gutui[i].i_imax = i_u != 0 ? (i_h - i_inaltime) / i_u : INT_MAX - 1;
    }

    /* Sorteaza gutuile */
    #ifdef DEBUG
    gutui_afiseaza( i_n, p_gutui );
    #endif
    gutui_merge_sort( i_n, p_gutui );
    #ifdef DEBUG
    gutui_afiseaza( i_n, p_gutui );
    #endif

    /* Vezi greutatea maxima */
    int i_gmax = gutui_calculeaza_greutate_maxima( i_n, p_gutui );

    free( p_gutui );

    /* Scrie rezultate */
    FILE *fout = fopen( OUTFILE, "w" );
    fprintf( fout, "%d", i_gmax );
    fclose( fout );
    
    return 0;
}