помогите решить задачу на Си

Задан размер массива действительных чисел и значения его элементов. Считая, что пары элементов представляют собой координаты точек на плоскости, проверить, могут ли все данные точки лежать на одной окружности и, если да, найти ее радиус.

В программе количество точек и координаты должен вводить пользователь

Рекомендация от препода: Размер массива определяется исходя из условия индивидуального задания. В тех случаях, когда максимальный размер исходного массива не оговорен, полагать, что он равен 20.

вот код

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main() {
    int n;
    printf("Enter the number of points: ");
    while ((scanf("%d", &n) != 1) || (n <= 0)) {
        printf("Invalid input. Please enter a positive integer: ");
        while (getchar() != '\n'); 
    }

    double x[n];
    double y[n];

    printf("Enter the coordinates of the points:\n");
    for (int i = 0; i < n; i += 2) {
        printf("Point %d: ", (i/2) + 1);
        while (scanf("%lf %lf", &points[i], &points[i + 1]) != 2) {
            printf("Invalid input. Please enter an integer: ");
            while (getchar() != '\n'); 
        }
    }
    
    double sum_x = 0, sum_y = 0;
    for (int i = 0; i < 2 * n; i += 2) {
        sum_x += points[i];
        sum_y += points[i+1];
    }
    double center_x = sum_x / n;
    double center_y = sum_y / n;

    double radius = 0;
    int S = 1;
    double distances[n]; 
    for (int i = 0; i < 2 * n; i += 2) {
        distances[i / 2] = sqrt(pow(points[i] - center_x, 2) + pow(points[i + 1] - center_y, 2));
        if (i == 0) {
            radius = distances[0];
        } else {
            if (fabs(distances[i / 2] - radius) > 0) {
                S = 0;
                break;
            }
        }
    }

    if (S) {
        printf("All points lie on the same circle.\n");
        printf("Radius: %.2f\n", radius);
    } else {
        printf("The points do not lie on the same circle.\n");
    }
    
    system("pause");
    return 0;
}

не понимаю как правильно расписать нахождение центра окружности, также преподаватель указал на то что неправильно объявлен массив, как можно это исправить?


Ответы (1 шт):

Автор решения: NunOfIt

Нахождение центра окружности и её радиуса по 3 точкам.

введите сюда описание изображения

Даны 3 точки: A(x1,y1), B(x2,y2) и C(x3,y3);

Пусть точка D(x0,y0) - центр окружности, а точки M(xm,ym) и N(xn,yn) - середины хорд AB и BC.

  1. В соответствие с теоремой о среднем перпендикуляре к хорде, линии DM и DN будут перпендикулярами.
  2. Запишем уравннение прямой AB: (x-x1) / (x2-x1) = (y-y1) / (y2-y1)
  3. Переходим от канонического уравнения прямой к уравнению с угловым коэффициентом (y = m_ab * x + b_ab): m_ab = (y2-y1) / (x2-x1); b_ab = y1 - x1(y2-y1)/(x2-x1)
  4. Соответственно, угловой коэффициент перпендикуляра DM к прямой AB будет равен: _m_ab = -1/m_ab = (x1-x2) / (y2-y1)
  5. Так же вычислим m_bc = (y3-y2) / (x3-x2) и _m_bc = (x2-x3) / (y3-y2)
  6. Запишем m_dm = (ym-y0) / (xm-x0); m_dn = (yn-y0) / (xn-x0)
  7. Составим систему { _m_ab = m_dm; _m_bc = m_dn }
  8. Получим: { y0 = (x1-x2)/(y2-y1) * x0 + ym - xm * (x1-x2)/(y2-y1); y0 = (x2-x3)/(y3-y2) * x0 + yn - xn * (x2-x3)/(y3-y2) }
  9. Пусть { y0 = am * x0 + dm; y0 = an * x0 + dn }
  10. Получим: x0 = (dn - dm) / (am - an); А y0 = am * x0 + dm, соответсвенно.
  11. Радиус равен дистанции между D и A; r = sqrt((x1-x0)^2 + (y1-y0)^2)
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

void swap(double* a, double* b) {
    double temp = *a;
    *a = *b;
    *b = temp;
}

bool has(double* beg, double* end, double x, double y) {
    for(double* it = beg; it < end; it += 2)
        if(*it == x && *(it + 1) == y)
            return true;
    return false;
}

double* scan(int* n) {
    double x, y;
    double *arr, *ptr;

    printf("Enter the number of points: ");
    scanf("%d", n);

    while(*n < 3) {
        printf("Wrong!!! Input must be greater or equal to 3!\nEnter the number of points: ");
        scanf("%d", n);
    }

    arr = (double*) malloc((*n << 1) * sizeof(double));
    ptr = arr;

    printf("Enter the coordinates of the points:\n");
    for(int i = 0; i < *n; ++i, ptr += 2) {
        // Считываем x и y
        printf("Point %d: ", i + 1);
        scanf("%lf %lf", &x, &y);

        // Проверка была ли точка уже введена
        if(has(arr, ptr + 1, x, y)) {
            printf("Point already exists! Input another one!\n");
            ptr -= 2;
            --i;
            continue;
        }

        // Записываем точку в массива
        *ptr = x;
        *(ptr + 1) = y;
    }
    *n = *n << 1;
    return arr;
}

// Проблема состоит в том, что иногда y2-y1 = 0 или y3-y2 = 0
// что приводит к x0 = NaN, y0 = NaN и r = NaN
// функция prep проходится по массиву и записывает в первые 6 ячеек
// массива значения которые не вызовут ошибок
void prep(double* arr, int n) {
    for(int i = 2; i < 6; i += 2) {
        if(arr[i - 1] != arr[i + 1]) { continue; }

        for(int j = 0; j < n; j += 2) {
            if(j == i || arr[i - 1] == arr[j + 1]) { continue; }
            
            (void) swap(&arr[i], &arr[j]);
            (void) swap(&arr[i + 1], &arr[j + 1]);
            i = 2;
        }
    }
}

// По теореме Пифагора расстояние между двумя точками:
// dist = sqrt((xn - x0)^2 + (yn - y0)^2)
double dist(double x0, double y0, double xn, double yn) {
    // Вычисляем (xn - x0)^2
    xn -= x0; xn *= xn;
    // Вычисляем (yn - y0)^2
    yn -= y0; yn *= yn;
    return sqrt(xn + yn);
}

void calc(double* arr, double* radius, double* x0, double* y0) {
    double xm = (arr[0] + arr[2]) / 2;
    double ym = (arr[1] + arr[3]) / 2;
    double am = (arr[0] - arr[2]) / (arr[3] - arr[1]);
    double dm = ym - xm * am;

    double xn = (arr[2] + arr[4]) / 2;
    double yn = (arr[3] + arr[5]) / 2;
    double an = (arr[2] - arr[4]) / (arr[5] - arr[3]);
    double dn = yn - xn * an;

    *x0 = (dn - dm) / (am - an);
    *y0 = am * (*x0) + dm;
    *radius = dist(*x0, *y0, arr[0], arr[1]);
}

int main() {
    int n;
    double *arr;
    double new_r, r, x0, y0;

    arr = scan(&n);
    (void) prep(arr, n);
    (void) calc(arr, &r, &x0, &y0);

    new_r = r;
    for(int i = 6; i < n; i += 2) {
        // Находим дистанцию от каждой новой точки до предполагаемого центра
        new_r = dist(x0, y0, arr[i], arr[i + 1]);

        // Если найденная дистанция не равна радиусу окружности
        // значит  данная точка не лежит на данной окружности
        // выходим из цикла
        if(new_r != r) { break; }
    }

    if(new_r == r) {
        printf("All points are on the same circle!\n");
        printf("Radius: %lf; Center: (%lf, %lf)\n", r, x0, y0);
    }
    else { printf("Not all points are on the same circle!\n"); }

    free(arr);
    return 0;
}
→ Ссылка