Sunteți pe pagina 1din 20

Lectia nr. 4.

– Probleme de geometrie computațională

Probleme de geometrie computațională

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

sau la dreapta lui P.

Soluție: Fie α unghiul format de dreapta OP si OX si β unghiul format de dreapta OQ si OX.


Daca Q se afla la dreapta atunci α < β --> tg(α) < tg(β), unde tg(α)=P.y/P.x, tan(β)=Q.y/Q.x

if(produs(p, q) > 0) cout << "dreapta";


else if(produs(p, q) < 0) cout << "stanga";
else cout << "Aceeasi directie";

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.

Astfel, am revenit la exercițiul anterior. Prin urmare intoarcere(A, B, C) = produs(B - A, C -


A). Daca funcția va returna 0, atunci C se afla pe dreapta AB.

int intoarce(struct punct a, struct punct b, struct punct c) {


struct punct p, q;
p = b - a;
Lectia nr. 4. – Probleme de geometrie computațională

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.

Soluție: Punctul C se va afla pe segmentul AB daca

int intre(int x1, int x2, int x3){


if((x1 <= x3 and x2 >= x3) or (x2 <= x3 and x1 >= x3))
return 1;
return 0;
}

int contine(struct punct a, struct punct b, struct punct c){


if(intoarce(a, b, c) == 0 and intre(a.x, b.x, c.x) and
intre(a.y, b.y, c.y))
return 1;
return 0;
}

........
if(contine(a, b, c) == 1)
out << "DA";
else
out << "NU";
........

2. Intersecții

2.1. Ecuația generala a dreptei


Fie dreapta d determinată de punctele A de coordonate (x1,y1) şi B de coordonate de
coordonate (x2,y2). Ecuația dreptei care trece prin punctele A si B este:

Din această ecuație pot fi calculați coeficienții ecuației generale a dreptei: Ax + By + C = 0.


Prin transformări elementare se obține:
Lectia nr. 4. – Probleme de geometrie computațională

Astfel avem:

2.2. Intersecția a doua drepte


Fie doua drepte d1 si d2 determinate de perechile de puncte P1(x1,y1),P2(x2,y2), respectiv
P3(x3,y3),P4(x4,y4). Pe baza celor enunțate mai sus ecuațiile celor 2 drepte vor fi:

Dreptele d1 si d2 coincid daca A1∗B2=A2∗B1 and A1∗C2=A2∗C1


Dreptele d1 si d2 sunt paralele daca A1∗B2=A2∗B1 and A1∗C2≠A2∗C1

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.

void lineIntersection(struct punct P1, struct punct P2, struct punct


P3, struct punct P4)
{
// Dreapta P1P2 cu ecuatia a1 * x + b1 * y + c1 = 0
int a1 = P2.y - P1.y;
int b1 = P1.x - P2.x;
int c1 = a1*(P1.x) + b1*(P1.y);

// Dreapta P3P4 cu ecuatia a2 * x + b2 * y + c2 = 0


int a2 = P4.y - P3.y;
int b2 = P3.x - P4.x;
int c2 = a2*(P3.x) + b2*(P3.y);

int determinant = a1 * b2 - a2 * b1;

if (determinant == 0) cout << "Dreptele sunt paralele!";

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ă

int intersectieSegmente(struct punct a, struct punct b, struct


punct c, struct punct d)
{
if(intoarce(a, b, c) * intoarce(a, b, d) < 0 and
intoarce(c, d, a) * intoarce(c, d, b) < 0 or (contine(a, b, c) or
contine(a, b, d) or contine(c, d, a) or contine(c, d, b)))
return 1;
return 0;
}

3. Aplicații geometrice elementare


3.1. Sa se verifice daca un punct D se găsește in interiorul triunghiului ABC
3.2. 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 încât punctul D sa fie in interiorul triunghiului ABPi
3.3. Se dau doua puncte A si B si o serie de N puncte in plan (P1, P2, ... Pn). Sa se
găsească un punct Pi astfel încât sa nu existe niciun alt punct in interiorul triunghiului
ABPi
3.4. Se dau o serie de N puncte in plan (P1, P2, ... Pn).Sa se determine daca acestea
formează un poligon convex.
3.5. Se dau o serie de N puncte in plan (P1, P2, ... Pn). Sa se determine daca punctul D se
găsește in interiorul poligonului convex determinat de punctele date.
3.6. Se dau o serie de N puncte in plan (P1, P2, ... Pn).Sa se determine daca punctul D se
găsește in interiorul poligonului concav determinat de punctele date.
3.7. Sa se verifice daca un punct A(x, y) se gaseste in interiorul unui cerc cu centrul in
origine si raza r.
Soluție: Un punct se găsește in interiorul cercului de raza r cu centrul in origine daca: x2+y2≤r2
int interior_cerc(struct punct A, int raza){
return A.x * A.x + A.y * A.y <= raza * raza;
}

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.

3.8. Se dau coordonatele a n puncte in plan si q intrebari. La fiecare întrebare se


precizează dimensiunea unei raze a unui cerc cu centrul in origine si trebuie sa se
Lectia nr. 4. – Probleme de geometrie computațională

precizeze numărul de puncte conținut de cercul cu raza data.


Date de intrare:
Fișierul punctepecerc.in conține pe prima linie numerele naturale n si q (1≤q,n≤105 ). Pe fiecare
din următoarele n linii se găsesc perechi de numerele naturale xi,yi(−109≤xi,yi≤109) reprezentând
coordonatele punctelor. Pe fiecare din următoarele q linii se găsește un număr natural r
(1≤r≤109)reprezentând raza unui cerc cu centrul in origine.
Date de ieșire:
Fișierul punctepecerc.out va conține q linii fiecare linie conținând răspunsul la o întrebare.
Exemplu:
punctepecerc.in punctepecerc.out
52 3
11 5
22
33
-1 -1
44
3
10

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)).

3.11. Sa se verifice daca un punct D se găsește in interiorul triunghiului ABC

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.

if((intoarce(a, b, d) == intoarce(b, c, d) and intoarce(b, c,


d) == intoarce(c, a, d)) or (contine(a, b, d) or contine(b,c,d) or
contine(a, c, d)))
out << "INSIDE";
else
out << "OUTSIDE";

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.

Aria unui triunghi


În determinarea ariei unui triunghi se poate folosi formula lui Heron:

În formulă, s reprezintă semiperimetrul triunghiului, iar a, b, c lungimile laturilor triunghiului.


Această formulă apare şi într-o altă formă, mult mai adecvată algoritmilor prin faptul că se evită
calcularea lungimii laturilor cu radical:
Lectia nr. 4. – Probleme de geometrie computațională

Î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:

Calcul determinat cu ajutorul codului

int det(int X1, int Y1, int X2, int Y2, int X3, int Y3) {
return (X2-X1)*(Y3-Y1) - (X3-X1)*(Y2-Y1);
}

Probleme pbinfo: 928

Aria unui patrulater


După cum am văzut în cazul unui triunghi, aria unui paralelogram ABCD este egală cu modulul
produsului vectorial al vectorilor reprezentați de 2 laturi neparalele.

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ă

Aria unui poligon


Pentru a calcula aria unui poligon oarecare A1A2A3..An, vom considera un punct P arbitrar ales în
plan. Vom "împărţi" poligonul în triunghiuri de forma PAiAi+1 (considerăm că A1=An+1) şi vom
calcula "aria cu semn" Ti a fiecărui triunghi (în formula ariei nu vom folosi funcţia de valoare
absolută). Distingem în acest moment două cazuri:
 Poligonul are vârfurile orientate trigonometric. Pentru fiecare latură "spre dreapta",
aria Ti corespunzătoare va fi negativă, iar pentru fiecare latură "spre stânga",

aria Ti corespunzătoare va fi pozitivă.

 Poligonul are vârfurile orientate antitrigonometric. Pentru fiecare latură "spre


dreapta", aria Ti corespunzătoare va fi pozitivă, iar pentru fiecare latură "spre

stânga", aria Ti corespunzătoare va fi negativă.


În ambele cazuri, efectuând suma algebrică a ariilor Ti vom obţine aria poligonului (deoarece ariile
negative vor "anula" zonele corespunzătoare ariilor pozitive care se află în afara poligonului).

Dacă alegem punctul P(0,0), fiecare arie Ti devine:


Lectia nr. 4. – Probleme de geometrie computațională

Formula finală devine:

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ă).

Problema pbinfo: 932

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:

In cazul in care dreapta nu se afla in plan, fiecare punct A ( x1 , x2 , x3 ,... Xn ) (pentru n


dimensiuni) de pe ea va îndeplini condițiile:

A nu se confunda cu ecuația planului:

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

Panta unei drepte


Panta unei drepte se poate defini ca fiind tangenta unghiului facut de dreapta cu orizontala, mai
exact cu orice dreapta paralela cu axa OX. Ea se calculeaza astfel:

sau

In a doua ecuatie a si b reprezinta coeficientii ecuatiei dreptei respective

Proprietati:
• Doua drepte care au pantele egale sunt ori paralele ori confundate.
• Doua drepte care au produsul pantelor egal cu -1 sunt perpendiculare.

Distanta dintre un punct si o dreapta


Pentru a calcula distanta care ne trebuie noua vom calcula panta dreptei d1 notata cu m1.
Acum vrem sa construim o dreapta d2 perpendiculara pe dreapta d1 care trece prin
punctul A. Stim ca m1*m2=-1 si de aici aflam usor m2 (panta dreptei d2). In acest moment
avem panta dreptei d2 si un punct care ii apartine. Avand aceste 2 informatii putem sa
calculam usor ecuatia ei si punctul de intersectie cu dreapta d1 (Vezi capitolul Drepte).
Lectia nr. 4. – Probleme de geometrie computațională

Distanta dintre dreapta si punct va fi egala cu distanta dintre punct si punctul de


intersectie al celor 2 drepte.
De asemenea exista si o formula pt a determina distanta de la un punct la o dreapta:
considerand punctul A(x0,y0) si dreapta d:ax+by+c=0, vom avea :

Distanta dintre un punct si un segment


Sa presupunem un punct A(x1,y1) si un segment determinat de punctele B(x2,y2) si C(x3,y3) si
vrem sa aflam distanta dintre punct si segment.
D=min(dist(A,B),dist(A,C)) in cazul in care perpendiculara din punctul A pe dreapta BC nu cade in
interiorul segmentului BC, altfel distanta va fi egala cu distanta dintre punctul A si dreapta BC, lucru
pe care l-am tratat mai sus.

Punct in interiorul unui triunghi


Se da un triunghi prin coordonatele varfurilor. Se cere sa se afiseze pentru un set de N puncte din
plan daca apartin sau nu interiorului triunghiului. Pentru a rezolva aceasta problema, sa
consideram triunghiul ABC si punctul P, interior acestuia.

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)

Punct in interiorul unui poligon oarecare


Se da un poligon oarecare cu N vârfuri si un punct P prin coordonatele carteziene. Se cere sa se
determine daca punctul P este in interiorul sau in exteriorul poligonului.
Se va trasa o semidreapta orizontala cu originea in punctul P. Daca aceasta semidreapta
intersecteaza un numar impar de muchii ale poligonului, atunci punctul se afla in interiorul
acestuia. Mentionam ca trebuie avut in vedere cazul in care semidreapta trece chiar printr-un varf
de poligon (capat a doua muchii). Vom considera imaginea următoare:
Lectia nr. 4. – Probleme de geometrie computațională

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.

Punct in poligon convex


Enunt: Se da un poligon convex cu N laturi si apoi M interogări caracterizate prin coordonatele unui
punct P, iar dumneavoastră trebuie sa determinați rapid daca punctul respectiv se afla sau nu in
interiorul poligonului.
Solutia 1
Se ia un vârf al poligonului, si se trasează cele n-3 diagonale care pornesc din el. Astfel poligonul
nostru se împarte in mai multe triunghiuri. Vom adaugă intr-un vector aceste drepte plus
cele 2 laturi care au originea in varful ales de noi si le sortam dupa panta. Cand primim un query
vom cauta binar dupa panta si vom afla intre ce diagonale se incadreaza acesta si verificam daca
punctul nostru se afla sau nu in triunghiul respectiv.

Punctul de intersectie a 2 drepte


Dupa cum am vazut, o dreapta reprezinta un loc geometric. Sa zicem ca avem 2 drepte d1 si d2 si
dorim sa aflam punctul A(x, y) cu propietatea ca acesta apartine atat dreptei d1, cat si dreptei d2.
Scriem ecuatiile celor 2 drepte:

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.

Scadem cele doua relatii si ajungem la o singura ecuatie cu o singura necunoscuta:

O data ce l-am aflat pe x, descoperirea celeilalte coordonate e destul de triviala:


Lectia nr. 4. – Probleme de geometrie computațională

Sa luam un exemplu:

In imaginea de mai sus punctele P1,..P6 reprezinta varfurile poligonului iar


punctele P7, P8, P9 reprezinta interogarile. Cu rosu sunt trasate diagonalele care delimiteaza
sectoarele, si le vom tine ca drepte, sortate dupa panta, impreuna cu dreptele suport pentru cele 2
laturi care au un capat in punctul P1. Astfel cand primim o interogare vom putea cauta binar si sa
aflam in ce sector se afla acesta. Pentru punctul P8 spre exemplu ne vom da seama ca se afla in
sectorul determinat de diagonalele care corespund punctelor P4 si P5. Astfel vom verifica daca
punctul P8 se afla in interiorul triunghiului determinat de punctele P1, P4, P5. Vom proceda
asemanator si pentru celelalte interogari cu mentiunea ca trebuie sa avem grija la cazurile in care
punctul nu se afla in nici unul din sectoare (P 9), insa asta se poate face usor cu o verificare inainte
de a porni cautarea binara.

Aceasta solutie are complexitate O(N logN + M logN).

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.

Solutie problema 936


#include <bits/stdc++.h>
#define N 105
#define PI 3.141592653

using namespace std;

ifstream fin ("infasuratoareconvexa.in");


ofstream fout ("infasuratoareconvexa.out");

struct punct
{
double x, y;
double unghi;
};

int n, k;
int st[N], top;
Lectia nr. 4. – Probleme de geometrie computațională

punct a[N], sol[N];

void Citire()
{
fin >> n;
for (int i = 1; i <= n; i++)
fin >> a[i].x >> a[i].y;
}

double prod_Vectorial(punct p, punct m, punct q)


{
double y1 = p.y - m.y;
double y2 = p.y - q.y;
double x1 = p.x - m.x;
double x2 = p.x - q.x;
return y2 * x1 - y1 * x2;
}

double dist(punct p, punct q)


{
return sqrt((p.x - q.x) * (p.x - q.x) + (p.y - q.y) * (p.y -
q.y));
}

bool cmp(punct p, punct q)


{
if (!prod_Vectorial(a[1], p, q))
return dist(a[1], p) > dist(a[1], q);
return prod_Vectorial(a[1], p, q) > 0;
}

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;

for (int i = 3; i <= k; i++)


{
while (top > 2 && prod_Vectorial(sol[st[top - 1]],
sol[st[top]], sol[i]) < 0)
top--;
st[++top] = i;
}
}

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;

fout << top << "\n";


for (int i = ind; i <= top; i++)
fout << sol[st[i]].x << " " << sol[st[i]].y << "\n";
for (int i = 1; i < ind; i++)
fout << sol[st[i]].x << " " << sol[st[i]].y << "\n";
}

int main()
{
Citire();
Sorteaza();
Select();
Solve();
Lectia nr. 4. – Probleme de geometrie computațională

Afisare();
return 0;
}

Probleme pbinfo:

Înfășurătoare convexa : 936, 2387

Paralelism si coliniaritate: 1609, 978

Puncte, distante: 927,929,930,933,934,1676,153

Unghiuri:931

Arii:928,932

Punct in poligon: 935

Anexe:

infasuratoarea convexa documentatie cex.pdf,

paper45.pdf(puncte laticeale)

S-ar putea să vă placă și