Cod sursa(job #2725710)

Utilizator trucker4lifeMoraru Radu-Andrei trucker4life Data 19 martie 2021 16:00:16
Problema Cele mai apropiate puncte din plan Scor 50
Compilator c-64 Status done
Runda Arhiva educationala Marime 4.12 kb
#include <stdio.h>
#include <math.h>
#include <stdlib.h>


typedef struct {
    int x, y, val;
} punct;

double calc_dist(int p1, int p2, punct *coord) {
    return sqrt(pow(coord[p1].x - coord[p2].x, 2) +
                pow(coord[p1].y - coord[p2].y, 2));
}

double calc_dist_min(int L, int R, int *sort_y, punct *coord);

int comparator(const void *a, const void *b);

int main() {
    int n;
    int *sort_y;
    punct *coord;
    double dist_min;

    FILE *fin = fopen("cmap.in", "r");
    FILE *fout = fopen("cmap.out", "w");

    if (fin == NULL) {
        printf("Nu a putut fi deschis fisierul cmap.in\n");
        return 0;
    }

    fscanf(fin, "%d", &n);
    coord = malloc((n+1) * sizeof *coord);

    // sort_y contine permutari ale indexilor
    sort_y = malloc((n+1) * sizeof *sort_y);

    for (int i = 1; i <= n; i++) {
        fscanf(fin, "%d %d", &(coord+i)->x, &(coord+i)->y);
        coord[i].val = i;
    }

    // sort dupa coordonata x
    qsort(coord+1, n+1, sizeof *coord, comparator);
    for (int i = 0; i <= n; i++) {
        sort_y[i] = i;
    }

    dist_min = calc_dist_min(1, n+1, sort_y, coord);
    fprintf(fout, "%.6f", dist_min);

    free(coord);
    return 0;
}

int comparator(const void *a, const void *b) {
    punct *p1 = (punct *)a;
    punct *p2 = (punct *)b;

    if (p1->x == p2->x) {
        if (p1->y == p2->y)     return 0;
        else if (p1->y > p2->y) return 1;
        return -1;
    }
    else if (p1->x > p2->x)     return 1;
    return -1;
}

double calc_dist_min(int L, int R, int *sort_y, punct *coord) {

    double d_min;

    if (R-L < 4) {
        double d_temp;
        // insertion sort dupa coordonata y
        for (int i = L+1; i < R; i++) {
            int t_y = sort_y[i];
            int j = i;

            while (j > L && coord[t_y].y < coord[sort_y[j-1]].y) {
                sort_y[j] = sort_y[j-1];
                j--;
            }
            sort_y[j] = t_y;
        }

        d_min = calc_dist(sort_y[L], sort_y[L+1], coord);
        // incerc toate posibilitatile
        for (int i = L; i < R; i++) {
            for (int j = L; j < i; j++) {
                d_temp = calc_dist(sort_y[i], sort_y[j], coord);
                if (d_temp < d_min) d_min = d_temp;     // trebuie sa initializez d_min;
            }
        }

        return d_min;
    }

    // INTERVAL MARE

    int M = (L+R-1)/2;
    double dL = calc_dist_min(L, M+1, sort_y, coord);
    double dR = calc_dist_min(M+1, R, sort_y, coord);

    d_min = dR;
    if (dL < dR) d_min = dL;

    double lim = d_min;

    int left = M+1, right = M+1;
    for (int i = L; i <= M; i++) {
        int p = sort_y[i];
        // DOAR daca coord[p].x >= coord[M].x - lim
        if (coord[p].x >= coord[M].x - lim) {
            // cuprind toate punctele cu y in intervalul [coord[p].y - lim, coord[p].y + lim]
            while (right < R && coord[sort_y[right]].y <= coord[p].y + lim) {
                right += 1;
            }

            while (left < right && coord[sort_y[left]].y <= coord[p].y - lim) {
                left += 1;
            }

            // calculez distanta de la p la toate punctele din interval
            for (int j = left; j < right; j++) {
                double temp_dist = calc_dist(sort_y[j], sort_y[i], coord);
                if (temp_dist < d_min) d_min = temp_dist;
            }
        }
    }

    // MERGE

    // similar cu merge sort, sortez local dupa coordonata y
    int *temp_arr = malloc((R-L) * sizeof *temp_arr);

    left = L;
    right = M+1;
    int i = 0;
    while (left < M+1 && right < R) {
        int lp = sort_y[left];
        int rp = sort_y[right];

        if (coord[lp].y < coord[rp].y) {
            temp_arr[i] = lp;
            left++;
        }
        else {
            temp_arr[i] = rp;
            right++;
        }
        i++;
    }

    // adaug restul
    while (right < R) {
        temp_arr[i] = sort_y[right];
        right++;
        i++;
    }
    while (left < M+1) {
        temp_arr[i] = sort_y[left];
        left++;
        i++;
    }
    // copiez din temp arr
    for (int it = 0; it < R-L; it++) {
        sort_y[L+it] = temp_arr[it];
    }

    free(temp_arr);

    return d_min;
}