Documente Academic
Documente Profesional
Documente Cultură
Puncte
1. Prezentare generala
Geometria computațională cuprinde algoritmii de rezolvare a problemelor de geometrie. În
cele ce urmează vom discuta de algoritmi care tratează doar punctele în plan, iar aceste
puncte au coordonate întregi. Punctele pot forma segmente, iar segmentele poligoane.
Un punct in plan il vom reprezenta printr-o structura cu doua câmpuri întregi, abscisa,
respectiv ordonata punctului. In unele probleme e nevoie si de numărul de ordine al
punctului.
struct punct{
int x, y;
int ord;//optional
};
Orice obiect geometric determinat de un sistem de puncte poate fi descris cu ajutorul unui
tablou unidimensional sau printr-o listă alocată dinamic, cu elemente de tip struct punct.
2. Concepte de baza
Produs încrucișat
Fie doua puncte P(p.x, p.y) si Q(q.x, q.y). Produsul încrucișat poate fi interpretat ca aria cu
semn a paralelogramului format din punctele (0, 0), P, Q, (p.x + q.x, p.y + q.y). Valoarea
produsului incrucisat se calculează astfel:
int produs(struct punct p, struct punct q) {
return p.y * q.x - q.y * p.x;
}
Lectia nr. 4. – Probleme de geometrie computațională
Aplicație: Fie un punct P. Sa se decidă daca raportat la origine un alt punct Q este la stânga
Aplicație:
Se dau trei puncte A, B, C. Sa se decida daca segmentul BC se intoarce la stanga sau la
dreapta fata de segmentul AB.
Soluție: Sa translatam cele 3 puncte astfel încât punctul A sa fie mutat in origine. Vom avea
A.x = 0,
A.y = 0,
B.x = B.x - A.x,
B.y = B.y - A.y,
C.x = C.x - A.x,
C.y = C.y - A.y.
q = c - a;
return produs(p, q);
}
Aplicație:
https://www.pbinfo.ro/probleme/929/punctsegment
Se dau trei puncte A, B, C. Sa se decidă daca punctul C se afla pe segmentul AB.
........
if(contine(a, b, c) == 1)
out << "DA";
else
out << "NU";
........
2. Intersecții
Astfel avem:
Daca niciuna din condițiile de mai sus nu sunt îndeplinite se poate calcula punctul de
intersecție. Se rezolva sistemul de ecuații prezentat valorile obţinute pentru x si y fiind
coordonatele punctului de intersecție.
else{
double x = (double)(b2*c1 - b1*c2)/determinant;
double y = (double)(a1*c2 - a2*c1)/determinant;
cout << x << " " << y;
}
}
2.3. Intersecția a doua segmente - https://www.pbinfo.ro/probleme/930/intersectiesegmente
Doua segmenta AB si CD se intersectează daca:
Lectia nr. 4. – Probleme de geometrie computațională
Observatii:
1. Daca originea cercului nu este in originea sistemului de coordonate, ci intr-un punct (x0,y0) se
poate face o translație a coordonatelor (x=x−x0,y=y−y0)si se aplica soluția precedenta.
2. Daca x2+y2=r2 atunci punctul se afla pe circumferinta cercului.
Soluție: O soluție de complexitate O(n * q) care pentru fiecare raza verifica cu un algoritm brute-
force cate puncte sunt situate in interiorul cercului nu va obține punctaj maxim.
Soluția eficienta presupune precalcularea tuturor distantelor xi2+yi2xi2+yi2 si stocarea acestora intr-
un vector d[]. Se sortează vectorul d si pentru fiecare raza ri se calculează cu o căutare binara cate
valori d[i] ≤ri.
for (int i = 1; i <= n; i++) {
in >> x >> y;
d[i] = x * x + y * y;
}
sort(d + 1, d + n + 1);
for(int i = 1; i <= q; i++){
in >> r;
//cautare binara pentru pozitia
//celui mai mare element din d <= r
out << bs(1, n, r) << "\n";
}
3.9. Se da un cerc cu raza r si centrul in origine. Sa se determine cate puncte laticeale
(puncte de coordonate întregi) se găsesc pe circumferința cercului.
Soluție: Conform celor afirmate anterior un punct de coordonate (x, y) se va afla pe circumferința
cercului cu centrul in origine si cu raza r daca x2+y2=r2. Vom verifica pentru fiecare x cu proprietatea
ca 0≤x2≤r2 daca diferența r2−x2 este pătrat perfect. Daca găsim o asemenea valoare vom avea 4
puncte laticeale aflate pe circumferința: (x, y), (x, -y), (-x,y) si (-x,-y).
Excepție daca x = 0 sau y = 0 avem numai doua puncte.
ans = 0;
for (int x = 0; x * x <= r; x++) {
y = r * r - x * x;
if(e_patrat_perfect(y)){
if(x == 0 or y == 0) ans = ans + 2;
else ans = ans + 4;
}
Lectia nr. 4. – Probleme de geometrie computațională
}
cout << ans;
3.10. Să se determine numărul de puncte de coordonate întregi prin care trece
segmentul determinat de punctele (0, 0) şi (M, N). De exemplu, pentru M = 9 şi N = 12
pe segment vor fi 4 puncte de coordonate întregi.
Putem considera doar cazurile în care 0 <= N <= M, daca N = 0 atunci evident avem M + 1 puncte pe
segment. Astfel trebuie să rezolvăm doar cazul în care 1 <= N <= M.
Evident că orice punct (x, y) pentru a fi pe segmentul nostru trebuie să satisfacă ecuaţia y = M / N * x.
Această ecuaţie are ca soluţie un număr natural doar dacă M * x se divide cu N, de aici dacă D =
cmmdc(N, M) atunci x se divide cu N/D, deci x de forma k * N/D => y = k * M/D.
Pentru ca punctul (x, y) să aparţină segmentului, trebuie ca 0 <= x <= N şi 0 <= y <= M astfel 0 <= k
<= D. Deci numărul de puncte de pe un segment de la (0, 0) la (N, M) este egal cu cel mai mare
divizor comun al numerelor M şi N la care adăugăm 1 . Putem determina acest număr în
complexitate în O(log (N + M)).
Punctul se afla in interiorul triunghiului daca parcurgând laturile triunghiului in ordinea A -> B -> C -
> A punctul de se afla in stânga tuturor segmentelor sau daca parcurgem in sens invers totdeauna in
dreapta laturilor.
3.12. Se dau trei puncte A, B, D si o serie de N puncte in plan (P1, P2, ... Pn). Sa se
gaseasca un punct Pi astfel incat punctul D sa fie in interiorul triunghiului ABPi
Lectia nr. 4. – Probleme de geometrie computațională
Se parcurg cele n puncte si pentru fiecare punct Pi se verifica daca punctul D se afla de aceeași parte a
segmentelor AB, BP si PA. Daca se găsește un astfel de punct se afișează coordonatele acestuia.
3.13. Se dau doua puncte A si B si o serie de N puncte (P1, P2, ... Pn). Sa se gaseasca un
punct Pi astfel incat sa nu existe niciun alt punct in interiorul triunghiului ABPi
Solutie: Vom incerca pe rând punctele. Sa presupunem ca am ajuns la punctul Pi. Vom putea exclude
punctele situate in stânga dreptei APi si punctele situate in dreapta dreptei BPi. Păstram celelalte
puncte. Vom lua următorul punct care nu a fost exclus si procedam identic. Vom continua algoritmul
pana când vom găsi un punct in care am exclus toate celelalte puncte.
3.14. Se dau o serie de N puncte in plan (P1, P2, ... Pn). Sa se determine daca acestea
formeaza un poligon convex.
3.15. Se dau o serie de N puncte in plan (P1, P2, ... Pn). Sa se determine daca punctul D
se gaseste in interiorul poligonului convex determinat de punctele date.
3.16. Se dau o serie de N puncte in plan (P1, P2, ... Pn). Sa se determine daca punctul D
se gaseste in interiorul poligonului concav determinat de punctele date.
4. Arii
Noțiunea de arie este una de bază în geometria analitică. Este necesară însă o prezentare a
diferitelor metode de a calcula ariile in contextul prelucrării datelor pe calculator.
În contextul geometriei vectoriale, modulul produsului vectorial a doi vectori o reprezintă aria
paralelogramului cuprins între vectori. Aplicând raţionamentul la triunghiuri, obţinem relaţia:
int det(int X1, int Y1, int X2, int Y2, int X3, int Y3) {
return (X2-X1)*(Y3-Y1) - (X3-X1)*(Y2-Y1);
}
Pentru un patrulater oarecare ABCD, putem considera M1, M2, M3, M4 mijloacele laturilor acestuia. Se
poate demonstra că patrulaterul M1M2M3M4 este un paralelogram cu aria jumătate din aria lui ABCD:
Lectia nr. 4. – Probleme de geometrie computațională
Această formulă reprezintă "aria cu semn" a poligonului (o arie pozitivă indică parcurgerea
vârfurilor în ordine trigonometrică, iar o arie negativă, parcurgerea in ordine antitrigonometrică).
Solutie:
#include <bits/stdc++.h>
using namespace std;
ifstream fin ("ariapoligonsimplu.in");
ofstream fout ("ariapoligonsimplu.out");
const int Nmax = 1005;
struct P
{
double x , y;
};
P a[Nmax];
int main()
{
int n;
double ar;
fin >> n;
for(int i = 0 ; i < n ; i++)
fin >> a[i] . x >> a[i] . y;
a[n] = a[0];
ar = 0;
for(int i = 0 ; i < n ; i++)
ar += (a[i] . x * a[i + 1] . y - a[i + 1] . x * a[i] . y);
fout << setprecision(1) << fixed << fabs ((double) ar / 2) << "\n";
fin.close();
fout.close();
return 0;
}
2. Drepte
Lectia nr. 4. – Probleme de geometrie computațională
Ecuațiile dreptei
Dreptele geometrice ce îndeplinesc ecuația dreptei. Cu alte cuvinte, ecuația unei drepte
reprezintă o relație care este respectata de toate punctele aflate pe dreapta. Forma generala a
ecuației unei drepte este:
Pentru simplitate, de aici înainte ne vom referi numai la drepte in plan. De menționat este faptul ca
daca trecem pe y in partea dreapta si impartim prin -b (consideram un caz general, nu cel nefericit
in care b=0), obtinem:
, unde
De asemenea, fiind date doua puncte A(x1, y1) si B(x2, y2), ecuatia dreptei determinate de ele se
poate scrie
Aceasta poate sa nu ne fie de prea mare ajutor, dar facand produsul mezilor cu extremii si
desfacand parantezele vom
obtine , de unde putem
deduce foarte usor cine sunt a, b, c din scrierile precedente.
Se stie ca orice dreapta imparte planul in 2 semiplane: cel cu puncte pentru care, daca aplicam
ecuatia, vom obtine o valoare strict pozitiva, si cel pentru care vom obtine o valoare strict
negativa. De aceea, daca avem o dreapta data prin 2 puncte A(x1, y1) si B(x2, y2) de pe aceasta,
atunci punctul C(x3, y3) va apartine dreptei AB daca si numai daca
sau
Proprietati:
• Doua drepte care au pantele egale sunt ori paralele ori confundate.
• Doua drepte care au produsul pantelor egal cu -1 sunt perpendiculare.
Observam ca vectorii ( AB, BP ), ( BC, CP ), ( CA, AP ) vor realiza mereu același tip de întoarcere
(in acest caz spre stânga). De aceea, determinanții:
det( ((xA,yA,1),(xB,yB,1),(xP,yP,1)) ),
det( ((xB,yB,1),(xC,yC,1),(xP,yP,1)) ),
det( ((xC,yC,1),(xA,yA,1),(xP,yP,1)) )
trebuie sa aiba acelasi semn. In caz contrar, P este in exteriorul triunghiului. In imaginea
precedenta, se observa ca in cazul punctului P', vectorii BC, CP fac o întoarcere la dreapta, deci
determinantul corespunzător nu va avea același semn cu ceilalți doi.
Aceasta idee poate fi generalizata pentru a fi determina daca un punct se afla in interiorul unui
poligon convex in O(N). Mai exact se calculează det( (x i,yi,1), (xi+1, yi+1, 1) (xp,yp,1) ) pentru i luând
valori de la 1 la N (cand i==N vom considera i+1=1) .
Punctul P(xp,yp) se afla in interiorul poligonului daca si numai daca toti determinanți au același
semn. ( "+" daca parcurgem poligonul in sens direct trigonometric, "-" altfel)
In cazul punctului P1, respectiv P2, semidreaptele intersectează 3, respectiv 1 latura (numere
impare) deci punctele se afla in interior. Semidreapta corespunzătoare lui P 3 intersecteaza o latura
si un varf de poligon. Pentru a rezolva acum aceasta problema, o solutie ar fi ca in loc sa alegem
semidreapta orizontala, sa luam o semidreapta random, astfel posibilitatea ca ea sa intersecteze
varfurile poligonului tinde spre 0. O alta solutie posibila - si mai usor de implementat - este sa
consideram ca facand parte dintr-o latura doar punctul cu coordonata y mai mare. Se garanteaza
astfel ca laturile care contin punctul de pe semidreapta vor fi numarate de numar par de ori (2 pt
punctul de sus, 0 pt punctul de jos) si ca, implicit, nu vor afecta corectitudinea algoritmului.
Am ajuns astfel la un sistem de 2 ecuatii cu 2 necunoscute. Pentru a ajunge la niste formule mai
directe de calculare a celor 2 coordonate vom inmulti prima relatie cu b2 si pe cea de-a doua cu b1.
Sa luam un exemplu:
Solutia 2
O alta solutie este sa impartim planul in fasii. Astfel din fiecare varf al poligonului vom
trasa o dreapta verticala. Acum pentru 2 drepte consecutive vom lua laturile care il intersecteaza
si le vom sorta crescator dupa y (e clar ca aceste laturi nu se intersecteaza deci putem alege orice
punct de pe latura si sa sortam dupa y-ul acestuia). Acum pentru a raspunde la interogari, vom
face 2 cautari binare. Vom cauta odata sa vedem in ce fasie se incadreaza punctul nostru, iar apoi
vom cauta inca odata binar sa vedem cate laturi din acea fasie sunt au y-ul mai mic decat punctul
nostru. Daca acest numar este impar atunci punctul este in interior, altfel este in exterior. De
mentionat ca aceasta solutie se poate aplica si la poligoane concave, de altfel in cazul poligoanelor
convexe nu pot fi decat 2 laturi pe o fasie si nu ar mai fi nevoie de a doua cautare binara.
Sa luam un exemplu:
Observam cu rosu dreptele care delimiteaza fasiile verticale. De asemenea vedem ca punctul P6 are
in fasia lui 2 laturi cu y-ul mai mic ca al lui si este in afara poligonului, spre deosebire de
punctul P7 care are o singura latura cu y-ul mai mic ca al sau si este in interior.
Avantajul acestei metode este ca functioneaza si in cazul poligoanelor concave, insa are
dezavantajul faptului ca pot exista interogari in care punctele sa se afle pe dreapta care
delimiteaza fasiile. Practic aceasta metoda este echivalenta cu metoda explicata mai sus, pentru a
verifica daca un punct se afla sau nu in interiorul unui poligon oarecare.
In cazul poligoanelor convexe complexitatea este aceeasi ca si la metoda de mai sus, insa
Lectia nr. 4. – Probleme de geometrie computațională
in cazul poligoanelor concave complexitatea teoretica e O(N^2 log N + M log N). Acest algoritm
poate fi aplicat in rezolvarea problemei poligon din arhiva de probleme.
Infasuratoarea convexa
Enuntul problemei:
Se da un set de puncte in plan, sa se determine un poligon convex de arie minima care contine
toate punctele in interiorul sau.
Rezolvare: O posibila solutie este sa fixam punctul cu abscisa minima ,iar in caz de egalitate luam
punctul cu ordonata minima, si sa translatam toate punctele pana cand acesta ajunge in punctul
de coordonate (0,0). Acum vom sorta punctele dupa formula unde x si y sunt coordonatele
punctului, iar in caz de egalitate dupa distanta fata de punctul (0,0). In cazul nefericit in
care x=0 vom considera ca . Apoi vom parcurge punctele in ordine si le vom introduce
intr-o stiva. Inainte sa introducem un punct in stiva trebuie insa sa ne uitam daca nu cumva
punctele st[vf-1] , st[vf] si P sunt in ordine invers trigonometrica ( st - stiva, vf - varful stivei, P -
punctul curent). Aici ne vom folosi de o alta proprietate a determinantului cu ajutorul caruia
determinam aria unui triunghi. Mai exact vom calcula
pentru st[vf-1] = (x1.y1) , st[vf]= (x2,y3), P(x3,y3). Daca D este negativ atunci inseamna ca unghiul cu
originea in st[vf] face o intoarcere la dreapta si trebuie scos din stiva. Repetam procedeul pana
cand ramanem cu un singur punct in stiva sau pana cand intalnim un D >= 0 dupa care adaugam
punctul in stiva. Dupa ce am terminat e posibil ca poligonul nostru inca sa fie convex deoarece nu
am verificat unghiul care are originea in st[vf], asa ca il vom calcula pe D pentru punctele st[vf-
1],st[vf],st[ 1 ] si vom scoate punctul din varf atata timp cat D va fi negativ. Punctele ramase
reprezinta infasuratoarea convexa a setului de puncte primite la intrare.
struct punct
{
double x, y;
double unghi;
};
int n, k;
int st[N], top;
Lectia nr. 4. – Probleme de geometrie computațională
void Citire()
{
fin >> n;
for (int i = 1; i <= n; i++)
fin >> a[i].x >> a[i].y;
}
void Sorteaza()
{
int ind = 1;
for (int i = 2; i <= n; i++)
if (a[i].x < a[ind].x || (a[i].x == a[ind].x && a[i].y
< a[ind].y))
ind = i;
Lectia nr. 4. – Probleme de geometrie computațională
swap(a[1], a[ind]);
sort(a + 2, a + n + 1, cmp);
}
void Select()
{
for (int i = 2; i <= n; i++)
{
if (a[i].y == a[1].y)
a[i].unghi = 90;
else
{
a[i].unghi = atan2(a[i].x - a[1].x, a[i].y - a[1].y)
* 180 / PI;
if (a[i].unghi < 0) a[i].unghi *= -1;
else a[i].unghi = 180 - a[i].unghi;
}
}
double first_ang = a[2].unghi, last_ang = a[n].unghi;
int ind;
for (int i = 2; i <= n; i++)
if (a[i].unghi == first_ang)
ind = i;
for (int i = 2, j = ind; i < j; i++, j--)
{
punct aux = a[i];
a[i] = a[j];
a[j] = aux;
}
sol[++k] = a[1];
for (int i = 2; i <= n; i++)
{
if (a[i].unghi == first_ang || a[i].unghi == last_ang)
sol[++k] = a[i];
else if (a[i].unghi != a[i - 1].unghi)
sol[++k] = a[i];
}
Lectia nr. 4. – Probleme de geometrie computațională
void Solve()
{
st[1] = 1;
st[2] = 2;
top = 2;
void Afisare()
{
int ind = 1;
for (int i = 2; i <= top; i++)
if (sol[st[i]].y < sol[st[ind]].y || (sol[st[i]].y ==
sol[st[ind]].y && sol[st[i]].x < sol[st[ind]].x))
ind = i;
int main()
{
Citire();
Sorteaza();
Select();
Solve();
Lectia nr. 4. – Probleme de geometrie computațională
Afisare();
return 0;
}
Probleme pbinfo:
Unghiuri:931
Arii:928,932
Anexe:
paper45.pdf(puncte laticeale)