N9

  • December 2019
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View N9 as PDF for free.

More details

  • Words: 5,392
  • Pages: 29
9.

Geometriai algoritmusok

Számos olyan gyakorlati számítási probléma van, amely megoldható olyan geometriai modellben, amelyben csak egyszeru˝ objektumok, pontok, egyenesek, szakaszok, szögek, szögtartományok, poligonok szerepelnek. Ilyen alapveto˝ feladatokat vizsgálunk.

9.1.

Alapfogalmak

R R

Pont: (x, y) ∈ × Szakasz Legyen p1 , p2 pont. A p1 és p2 pont által meghatározott szakasz:

p1 p2 = {p = (x, y) : x = α p1 .x + (1 − α)p2 .x, y = α p1 .y + (1 − α) p2 .y), α ∈ R, 0 ≤ α ≤ 1} → Ha p1 és p2 sorrendje számít, akkor irányított szakaszról beszélünk, jele: − p− 1 p2 . Egyenes Egyenes megadása: 1. y = m x + b egyenlettel: azon (x, y) pontok halmaza, amelyekre teljesül az egyenlet. 2. a x + b y + c = 0 egyenlettel. 3. Egyenes megadása két pontjával: e(p1 , p2 )

9.2.

Feladat: Pontok összekötése zárt, nem-metszo˝ poligonná.

Adott a síkon n darab pont, amelyek nem esnek egy egyenesre. A pontok (x, y) koordinátáikkal adottak, amelyek egész számok. A pontokat a 1, . . . , n számokkal azonosítjuk. Kössünk össze pontpárokat egyenes szakaszokkal úgy, hogy olyan zárt poligont kapjunk, amelyben nincs metszo˝ szakaszpár. Egy ilyen zárt, nem-metszo˝ poligon megadható a pontok azonosítóinak egy felsorolásával: a felsorolásban egymást követo˝ pontokat kötjük össze egyenes szakaszok˝ kal, továbbá, az utolsót az elsovel is összekötjük.

Bemeneti specifikáció A poligon.be szöveges állomány elso˝ sora a pontok n (3 < n < 100000) számát tartalmazza. A további n sor mindegyike két egész számot tartalmaz, egy pont x és y koordinátáit, (−20000 ≤ x, y ≤ 20000). A pontok nem esnek egy egyenesre.

Kimeneti specifikáció A poligon.ki szöveges állományba a bemenetre kiszámított zárt, nem-metszo˝ poligont leíró sorozatot kell kiírni.

1

Példa bemenet és kimenet poligon.be

poligon.ki

6 2 1 0 3 2 2

3 1 4 5 6 2 0 4 2 2 4 6

Megoldás Válasszuk ki a legkisebb x-koordinátájú pontot, ha több ilyen van, akkor ezek közül válasszuk a legkisebb y-koordinátájút. Ezt nevezzük (bal-alsó) sarokpontnak és jelöljük Q-val. Húzzunk (fél) egyenest a Q sarokpontból minden ponthoz. ˝ Rendezzük az egyeneseket a Q ponton áthaladó, x-tengellyel párhuzamos egyenessel bezárt (elojeles) szög alapján. ˝ és pi elobb ˝ legyen mint p j akkor és csak akkor, ha Rendezzük a pontokat úgy, hogy a Q sarokpont legyen az elso, pi

φ(Q, pi) Q

Q

φ(Q, pi)

pi

˝ 1. ábra. A pi ponthoz tartozó elojeles szög: φ(Q, pi ). A φ(Q, pi ) < φ(Q, p j ), vagy φ(Q, pi ) = φ(Q, p j ) és pi közelebb van Q-hoz, azaz pi .x < p j .x, vagy φ(Q, pi ) = φ(Q, p j ) és pi .x = p j .x és pi .y < p j .y. Ha ebben a sorrendben kötjük össze a pontokat, kivéve, hogy az utolsó egyenesen lévo˝ pontokat fordított sorrendben vesszük, akkor egy zárt, nem metszo˝ poligont kapunk. Hogyan döntheto˝ el, hogy φ(Q, pi ) < φ(Q, p j )? ˝ tehát Minden i > 1-re − π2 < φ(Q, pi ) ≤ π2 és ebben a tartományban a tangens függvény szigorúan monoton növekvo, φ(Q, pi ) < φ(Q, p j ) akkor és csak akkor, ha

tan(φ(Q, pi )) =

p j .y − Q.y pi .y − Q.y < = tan(φ(Q, p j )) pi .x − Q.x p j .x − Q.x

Mivel Q sarokpont, így pi .x − Q.x ≥ 0 és p j .x − Q.x ≥ 0, tehát

φ(Q, pi ) < φ(Q, p j ) akkor és csak akkor, ha

(pi .y − q.y)(p j .x − Q.x) < (p j .y − Q.y)(pi .x − Q.x) 2

pj

pi

p j .y − Q.y pi.y − Q.y

pi.x − Q.x Q

p j .x − Q.x

2. ábra. A φ(Q, pi ) és φ(Q, p j ) szögek viszonya.

˝ p j -t akkor és csak akkor, ha Tehát a pontok rendezése: pi megelozi

(pi .y − Q.y)(p j .x − Q.x) < (p j .y − Q.y)(pi .x − Q.x) ∨ (pi .y − Q.y)(p j .x − Q.x) = (p j .y − Q.y)(pi .x − Q.x) ∧ pi .x < p j .x ∨

(1)

(pi .y − Q.y)(p j .x − Q.x) = (p j .y − Q.y)(pi .x − Q.x) ∧ pi .x = p j .x ∧ pi .y < p j .y

(3)

(2)

A sík pontjainak ábrázolására a P ONT osztályt használjuk.

public class Pont{ double x, y;//a pont x- és y-koordinátája int az; //a pont azonosítója Pont(double x, double y, int az){ this.x=x; this.y=y; this.az=az; } Pont(double x, double y){ this.x=x; this.y=y; } Pont(){} } Tegyük fel, hogy van olyan S AROK R ENDEZ eljárásunk, amely a P ponthalmazt rendezi a bal-alsó sarokpontjára vonat˝ kozó polárszög szerint. Ekkor a feladat megoldása a következoképpen adható meg.

public class Poligon{ public static int[] Osszekot(Pont[] P){ int n=P.length; int[] S=new int[n]; //bal-alsó sarokpont szerinti polár-szög rendezés Geom.SarokRendez(P); for (int i=0; i
//egy helyes sorrend: S[0..i],S[n-1]..S[i+1] int j=n-1; i++; while (i<j){ int x=S[i]; S[i++]=S[j]; S[j--]=x; } return S; } } A S AROK R ENDEZ eljárás a kupacrendezést használva rendezi a ponthalmazt. A R ENDEZ .K UPAC R END 1 eljárásnak paraméterként adjuk meg az r rendezési relációt, ami az (1-3) képletet valósítja meg.

public int int for

static void SarokRendez(Pont[] P){ mi=0; n=P.length; (int i=1; i
} Tehát a teljes feladat megoldása:

public class Polifelad{ public static void main (String[] args)throws IOException{ Pont[] P=BeOlvas(); int[] S=Poligon.Osszekot(P); KiIr(S); } public static Pont[] BeOlvas()throws IOException{ Scanner bef = new Scanner(new File("poligon.be")); int n=bef.nextInt(); bef.nextLine(); Pont[] P=new Pont[n]; for (int i=0; i
static void KiIr(int[] S)throws IOException{ PrintWriter kif=new PrintWriter( new BufferedWriter( new FileWriter("poligon.ki") ) ); for (int x:S) kif.print(x+" "); kif.println(); kif.close(); } } ˝ Gyakran elofordul, hogy a síkon adott p1 és p2 pontra el kell dönteni, hogy a p1 ponthoz képest a p2 pont milyen forgásirányba esik. Tekintsük a 3. ábrán látható p1 és p2 vektorokat. A p1 × p2 keresztszorzat a (0, 0), p1 , p2 és a ˝ ˝ p1 + p2 = (p1 .x + p2 .x, p1 .y + p2 .y) pontok által alkotott paralelogramma elojeles területeként értelmezheto.

x2

x1

p1 + p2

y1 p2

y2

y2 p1 y1 x2

x1 (0, 0)

˝ 3. ábra. A paralelogramma elojeles területe:

T = (x1 + x2 )(y1 + y2 ) − x1 y1 − x2 y2 − x2 y1 − x2 y1 = x1 y1 + x1 y2 + x2 y1 + x2 y2 − x1 y1 − x2 y2 − x2 y1 − x2 y1 = x1 y2 − x2 y1



p1 × p2

x1 x2 = det y1 y2 = x1 y2 − x2 y1



= −p2 × p1 . p1 × p2 > 0 ⇔ p2 az órajárással ellentétes irányban van p1 -hez képest. p1 × p2 = 0 ⇔ a (0, 0), p1 és p2 pontok egy egyenesre esnek (kollineárisak). p1 × p2 < 0 ⇔ p2 az órajárás irányban van p1 -hez képest. Még általánosabban, adott két csatlakozó irányított sza→ −−→ −−→ −−→ kasz, − p− 0 p1 és p1 p2 , milyen irányba fordul p1 p2 a p0 p1 -hez viszonyítva? ˝ A válasz (p1 − p0 )×(p2 − p0 ) = (p1 .x − p0 .x)(p2 .y− p0 .y)−(p2 .x − p0 .x)(p1 .y− p0 .y) keresztszorzat elojele alapján megadható. 5

y

p1 + p2

y

p p2 (0, 0)

x

p1 (0, 0)

x (b)

(a)

˝ 4. ábra. (a) A p1 és p2 vektorok keresztszorzata a paralelogramma elojeles területe. (b) A világos tartomány azokat a ˝ órajárással egyezo˝ irányba esnek, a sötétebb pedig azokat, amelyek órajárással pontokat tartalmazza, amelyek a p-tol ˝ ellentétes irányba esnek p-tol.

p2

p2 p1

p1

p0

p0

5. ábra. Csatlakozó szakaszok forgásiránya.

6

(p1 − p0 ) × (p2 − p0 ) > 0 : (p1 − p0 ) × (p2 − p0 ) = 0 : (p1 − p0 ) × (p2 − p0 ) < 0 :

− → p− 1 p2 balra fordul, − → −−→ p− 0 p1 és p1 p2 kollineárisak, − p−→ p jobbra fordul. 1 2

public static int ForgasIrany(Pont p0, Pont p1, Pont p2){ /** Kimenet: +1 ha p0->p1->p2 balra fordul, * 0 ha p0,p1 és p2 kollineárisak, * -1 ha p0->p1->p2 jobbra fordul. */ double p1xp2=(p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y); return (int)Math.signum(p1xp2); } Annak eldöntése, hogy a kollineáris p0 , p1 , p2 pontok esetén p1 közelebb van-e p0 -hoz, mint p2 :

p1 max(p1.y,p2.y) q

q.y

min(p1.y,p2.y)

p2

min(p1.x,p2.x)

q.x

max(p1.x,p2.x)

6. ábra. A q pont a p1 p2 szakaszra esik, ha p1 , p2 és q kollineárisak és min(p1 .x, p2 .x) ≤ q.x ≤ max(p1 .x, p2 .x) és min(p1 .y, p2 .y) ≤ q.y ≤ max(p1 .y, p2 .y).

public static boolean Kozel(Pont p0, Pont p1, Pont p2){ /** *Feltétel: (p0,p1,p2) kollineáris *Kimenet: p1 közelebb van p0-hoz, mint p2 */ return Math.abs(p1.x-p0.x)<Math.abs(p2.x-p0.x) || Math.abs(p1.y-p0.y)<Math.abs(p2.y-p0.y) ; } public static boolean Kozte(Pont p1, Pont p2, Pont q){ return Math.abs(p1.x-q.x)<=Math.abs(p2.x-p1.x) && Math.abs(p2.x-q.x)<=Math.abs(p2.x-p1.x) && Math.abs(p1.y-q.y)<=Math.abs(p2.y-p1.y) && Math.abs(p2.y-q.y)<=Math.abs(p2.y-p1.y) ; } A F ORGAS I RANY és a KOZEL felhasználásával megadhatjuk a bal-alsó sarokponthoz viszonyított polárszög szerinti rendezés rendezési relációját. 7

/** *A this.sarok bal-alsó sarokponthoz viszonyított pollárszög szerinti rendezés *rendezési relációja */ public class SarokRend implements Comparator{ Pont sarok; //a ponthalmaz bal-alsó sarokpontja public int compare(Pont p1, Pont p2){ if (p1.x==p2.x && p1.y==p2.y) return 0; int forg=Geom.ForgasIrany(sarok,p1,p2); return (forg>0 || forg==0 && Geom.Kozel(sarok,p1,p2)) ? -1:1; } SarokRend(Pont q){ sarok=new Pont(q.x,q.y); } SarokRend(){ sarok=new Pont(); } } ˝ Hasonlóképpen, tetszoleges q pontra vonatkozó polárszög szerinti rendezés rendezési relációja is megadható a F OR GAS I RANY és a KOZTE felhasználásával. 13 11 14

12 2

q

1

9

3

10

7

4

8

5 6

7. ábra. A q pontra vett polárszög szerinti rendezés. A pont mellé írt szám a pontnak a rendezésbeli sorszáma.

/** A this.polar ponthoz viszonyított pollárszög szerinti rendezés * rendezési relációja */ public class PolarRend implements Comparator{ private Pont polar; public int compare(Pont p1, Pont p2){ if (p1.x==p2.x && p1.y==p2.y) return 0; int forg=Geom.ForgasIrany(polar,p1,p2); 8

switch (forg){ case -1: return (p1.y<=polar.y && p2.y>polar.y) ? -1:1; case 0 : return Geom.Kozte(polar,p2,p1) || Geom.Kozte(p1,p2,polar) && (p1.y<polar.y || p1.y==polar.y && p1.x<polar.x) ? -1:1; case 1 : return (p1.y<=polar.y || p2.y>polar.y) ? -1:1; default : return 0; } }

9.3.

Feladat: Pont helyzetének megállapítása.

Adott a síkon egy zárt, nem-metszo˝ poligon a csúcsainak p1 , . . . , pn órajárással ellentétes felsorolásával és adott egy q pont. Eldöntendo˝ a q pontnak a poligonhoz képesti helyzete, azaz, hogy a belsejéhez tartozik-e, az oldalán van-e, avagy külso˝ pont? Megoldás Válasszunk egy olyan q0 pontot, amely biztosan nem tartozik a poligon belsejéhez és a poligon egyetlen csúcsa sem esik a q0 q szakaszra, legfeljebb ha q megegyezik valamelyik csúccsal. (Van ilyen pont.) ˝ A q0 külso˝ pont Ha a q0 q szakasz a poligon páratlan számú oldalát metszi, akkor q belso˝ pont, egyébként külso.

q

q0

8. ábra. A q0 q szakasz a poligon páratlan sok oldalát metszi, tehát belso˝ pont.

választása. Legyen q0 .y = max{pi .y|pi .y < q.y, i = 1, . . . n} és q0 .x = min{pi .x|i = 1, . . . n} − 1. Ha a poligonnak nincs olyan csúcspontja, amelynek y-koordinátája kisebb, mint q.y, akkor q biztosan külso˝ pont. A q0 pont ilyen választása esetén legfeljebb a q pont esik a poligon valamelyik oldalára, amikor is q nem belso˝ pont lesz. ˝ Ezt az esetet külön ellenorizzük. Egyébként, a poligon bármely pi pi+1 oldalának akkor és csak akkor van közös pontja a q0 q szakasszal, ha pi és pi+1 az e(q0 , q) egyenes különbözo˝ oldalára esik és a q0 és q pont az e(pi , pi+1 ) egyenes különbözo˝ oldalára esik. Ez a feltétel a F ORGÁS I RANY eljárás felhasználásával egyszeruen ˝ kiszámítható.

/** a p1-p2 szakaszon van-e a q pont? */ 9

q

q0

9. ábra. A poligonnak több csúcsa is a q0 q szakaszra esik.

q

q0

10. ábra. A q0 pont választása:q0 .y = max{pi .y|pi .y < q.y, i = 1, . . . n} és q0 .x = min{pi .x|i = 1, . . . n} − 1.

p1 max(p1.y,p2.y) q

q.y

min(p1.y,p2.y)

p2

min(p1.x,p2.x)

q.x

max(p1.x,p2.x)

11. ábra. A q pont a p1 p2 szakaszra esik, ha p1 , p2 és q kollineárisak és |q.x − p1 .x| ≤ |p2.x − p1.x| és |q.x − p2 .x| ≤ |p2.x − p1.x|

10

public static boolean Szakaszon(Pont p1, Pont p2, Pont q){ double fir=(p1.x-q.x)*(p2.y-q.y)-(p2.x-q.x)*(p1.y-q.y); return fir==0.0 && Math.abs(q.x-p1.x)<=Math.abs(p2.x-p1.x) && Math.abs(q.x-p2.x)<=Math.abs(p2.x-p1.x) && Math.abs(q.y-p2.y)<=Math.abs(p2.y-p1.y) && Math.abs(q.y-p2.y)<=Math.abs(p2.y-p1.y) ; } /** Kimenet: -1 ha a q pont a poligon belsejében van, * 0 az oldalán van, * +1 ha kivül van */ public static int PontHelyzete(Pont[] P, Pont q){ int n=P.length; double y0=q.y; double x0=P[0].x; for (int i=1; iy0 || y0==q.y) ) y0=P[i].y; if (P[i].x<x0) x0=P[i].x; } Pont q0=new Pont(x0-1,y0); int metsz=0; for (int i=0; i
A algoritmus futási ideje legrosszabb esetben is a poligon csúcsainak n számával arányos, tehát O(n).

9.4.

Metszo˝ szakaszpárok

˝ hogy metszi-e egymást adott p1 p2 és q1 q2 szakasz? Eldöntendo,

public class Szakasz{ Pont bal, jobb; //a szakasz bal- és jobb-végpontja int az; //a szakasz azonisítója Szakasz(Pont b, Pont j, int a){ 11

p2

p2

p2

q2 q2 q1 p1

q1 q1

p1

p1

q2

p2

p1

q2 q2 p1

p2 q1 q1

12. ábra. Szakaszpárok metszésének öt lehetséges esete.

bal=b; jobb=j; az=a; } Szakasz(Pont b, Pont j){ bal=b; jobb=j; } Szakasz(){} } public static boolean SzakaszParMetsz(Szakasz s1, Szakasz s2){ int fpq1=ForgasIrany(s1.bal,s1.jobb,s2.bal); int fpq2=ForgasIrany(s1.bal,s1.jobb,s2.jobb); int fqp1=ForgasIrany(s2.bal,s2.jobb,s1.bal); int fqp2=ForgasIrany(s2.bal,s2.jobb,s1.jobb); return (fpq1*fpq2<0) && (fqp1*fqp2<0) || fpq1==0 && Kozte(s1.bal,s1.jobb,s2.bal) || fpq2==0 && Kozte(s1.bal,s1.jobb,s2.jobb) || fqp1==0 && Kozte(s2.bal,s2.jobb,s1.bal) || fqp2==0 && Kozte(s2.bal,s2.jobb,s1.jobb); }

9.5.

Ponthalmaz konvex burka

˝ poligon konvex, ha bármely két belso˝ pontját összeköto˝ szakasz minden pontja Definíció. Egy egyszeru˝ (nem metszo) a poligon belsejében, vagy határán van. Definíció. Egy P = {p1 , . . . , pn } ponthalmaz konvex burka az a legszukebb ˝ Q konvex poligon, amely a ponthalmaz minden pontját tartalmazza . Megoldás Graham-féle pásztázással Elso˝ lépésként rendezzük a ponthalmazt polárszög szerint, majd minden egyenesen csak a sarokponttól legtávolabbi pontot hagyjuk meg, a többit töröljük. Az így törölt pontok biztosan nem lehetnek csúcspontjai a konvex buroknak. Legyen hq1 , . . . , qm i az így kapott pontsorozat polárszög szerinti rendezésben. Mindaddig, amíg van három olyan −−−→ −−−→ cirkulárisan egymást követo˝ qi , qi+1 qi+2 pont, hogy − q− i+1 qi+2 jobbra fordul qi qi+1 -hez képest, hagyjuk el a qi+1 pontot. Az algoritmus futási ideje O(n lg n), ha a polárszög szerinti rendezést olyan algoritmussal valósítjuk meg amelynek

12

13. ábra. Ponthalmaz konvex burka.

futási ideje O(n lg n).

/** *Konvex burok Graham-féle páztázó algoritmusa *Bemenet: Pont[] P ponthalmaz *Kimenet: m: a konvex burok pontjainak száma * P[0..m-1] tartalmazza a konvex burok pontjait */ public static int GrahamKB(Pont[]P){ int n=P.length; Pont x; SarokRendez(P); int m=1; for (int i=2; i0 && ForgasIrany(P[m-1],P[m], P[i])<=0) m--; m++; x=P[m]; P[m]=P[i]; P[i]=x; } return m; }

13

14. ábra. A pontok halmazának rendezése polárszög szerint.

14

15. ábra. Minden egyenesen csak a legtávolabbi pont marad meg.

15

9.6.

˝ Érinto˝ egyenes keresése lineáris idoben

9.1. definíció. Legyen P ponthalmaz, a ∈ P és q egy pont. Azt mondjuk, hogy az e(q, a) a P ponthalmaz jobboldali → érinto˝ (támasztó) egyenese, ha P minden pontja − qa-tól nem jobbra van. Hasonlóan, az e(q, a) a P ponthalmaz baloldali → érinto˝ (támasztó) egyenese, ha P minden pontja − qa-tól nem balra van.









b







a

















q

16. ábra. e(q, a) a P ponthalmaz jobboldali, e(q, b) pedig a baloldali érinto˝ egyenese.

Nyilvánvaló, hogy akkor és csak akkor létezik adott q ponton átmeno˝ érinto˝ egyenes, ha q a P ponthalmaz konvex burkán kivül, vagy az oldalán van. Feladat: érinto˝ egyenes meghatározása. Bemenet: P ponthalmaz, q pont Kimenet: 1. (a, 0, 0), ha P minden pontja az e(q, a) egyenesre esik 2. (a, b, 0), ha q a P konvex burkán kivül van, és ekkor e(q, a) jobboldali, e(q, b) pedig baloldali érinto˝ egyenes 3. (a, b, c), ha q a P konvex burkán belül van, és ekkor a, b és c olyan három pontja P-nek, hogy q az 4(a, b, c) háromszög belsejébe, vagy oldalára esik, de P egyetlen más pontja sem esik a háromszögbe sem oldalára.

16

c

q a b 17. ábra.

17

public static int[] Erinto(Pont[] P, Pont q){ /* Bemenet: P ponthalmaz, q pont Kimenet: (i,0,0) ha P minden pontja az e(q,P[i+1]) egyenesre esik (a,b,0) ha q a P konvex burkán kívül van, és ekkor az e(q,a) és e(q,b) a két érint˝ o egyenes (a,b,c) ha q a P konvex burkán belül van, és ekkor (a,b,c) olyan háromszög, hogy q a háromszögben van, és a,b és c kivételével P egyetlen pontja sem esik a háromszögbe, sem oldalára. */ int n=P.length; int[] abc={0,0,0}; Pont a=P[0]; Pont b=null; Pont c=null; int firqa,firqb, firqc; int i=0; for (i=1; i=0 || firqa<=0 && firqb>0){//1.eset c=P[j]; break; }else if (firqa<0 && firqb<0){//2.eset a=P[j]; }else if (firqa>0 && firqb>0){//3.eset b=P[j]; }//else nincs mit tenni, sem a, sem b nem vátozik } //ha c==null, akkor q kivül van, és ekkor e(q,a) és e(q,b) érint˝ o egyenes if (c==null){ abc[0]=a.az; abc[1]=b.az; abc[2]=0; return abc; } //Az (a,b,c) háromszög tartalmazza a q pontot, finomítás: for (int i=0; i=0 && Geom.ForgasIrany(b,c,P[i])>=0 && Geom.ForgasIrany(c,a,P[i])>=0){ firqa=Geom.ForgasIrany(q,a,P[i]); 18

firqb=Geom.ForgasIrany(q,b,P[i]); firqc=Geom.ForgasIrany(q,c,P[i]); if (firqb<=0 && firqc>=0){ a=P[i]; }else if (firqa>=0 && firqc<=0){ b=P[i]; }else { c=P[i]; } } abc[0]=a.az; abc[1]=b.az; abc[2]=c.az; return abc; }//Erinto

9.7.

Feladat: Ponthalmaz legtávolabbi pontpárja.

Adott a síkon egy P = {p1 , . . . , pn } ponthalmaz. Határozzuk meg a ponthalmaz egy legtávolabbi pontpárját! Megoldás. n (n−1) A naiv algoritmus, amely minden pontpárra kiszámítja azok távolságát, futási ideje O(∑n−1 = O(n2 ). i=1 i) = 2 Konvex burok alkalmazásával O(n lg n) ideju˝ algoritmust adhatunk.

9.2. lemma. A legtávolabbi pontpár P konvex burkának két pontja lesz. Definíció A P ponthalmaz átellenes pontpárja olyan pi és p j pontpár, hogy ha van olyan pi -n és p j -n átmeno˝ egyenes, amelyek párhuzamosak és a P ponthalmaz minden pontja a két egyenes közé esik. Konvex poligon összes átellenes pontpárjának meghatározása görgetéssel. Legyen P = hp1 , . . . , pm i a konvex poligon csúcspontjainak órajárással ellentétes felsorolása. Legyen pi a konvex poligon legkisebb y-koordinátájú pontja, ha ketto˝ ilyen van, akkor ezek közöl válasszuk a legnagyobb x-koordinátájút. Legyen továbbá p j pedig a legnagyobb y-koordinátájú pontja, ha ketto˝ ilyen van, akkor ezek közül válasszuk a legkisebb x-koordinátájút. pi és p j nyilvánvalóan átellenes pontjai a poligonnak. ˝ Az összes átellenes pontpár lineáris idoben meghatározható görgetéssel. Ha az e(pi , pi+1 ) egyenes hajlásszöge p j

p j+1

pi+1 pi

18. ábra. Görgetés

kisebb, mint az e(p j , p j+1 ) egyenes hajlásszöge, akkor a pi+1 és p j is átellenes pontpár lesz, egyébként a pi p j+1 ˝ Forgassuk el balra a 14.ábrán látható pi és p j pontokon átmeno˝ lesz átellenes pontpár. (a +1 modulo m értendo). − − − → vagy a − → −→ ˝ párhuzamos egyeneseket amíg valamelyik a pi pi+1 p−j − p− érjük el a − p− i pi+1 oldalt, j+1 oldalra nem ér. Ha elobb 19

akkor i := i + 1, egyébként j := j + 1. Folytassuk ezt mindaddig, amíg vissza nem érünk a kezdetben választott két átellenes ponthoz. A szögek viszonya eldöntheto˝ a következo˝ kifejezéssel: F ORGAS I RANY(p j+1 , pi+1 − pi + p j+1 , p j ) > 0 Következmény n elemu˝ ponthalmaz egy legtávolabbi pontpárja O(n lg n) ideju˝ algoritmussal kiszámítható. Következmény n elemu˝ ponthalmaz vastagsága O(n lg n) ideju˝ algoritmussal kiszámítható.

public class LTavolPontpar{ private static Pont Eltol(Pont q1, Pont q2, Pont q3){ return new Pont(q3.x-q2.x+q1.x, q3.y-q2.y+q1.y,0); } /**@return A P ponthalmat legtavolabbi pontpárja */ public static PontPar ParKeres(Pont[] P){ int n=P.length; int m=Geom.GrahamKB(P); int i0=0; int j0=0; int i,j,ii,jj; double irany; /* A konvex burok két átellenes pontjának meghatározása */ for (int k=1; k<m; k++){ if (P[k].yP[i0].x))i0=k; if (P[k].y>P[j0].y||(P[k].y==P[j0].y&&P[k].x0){ i=ii; ii=(i+1)%m; }else { //irany>=0 j=jj; jj=(j+1)%m; } ujtav=(P[i].x-P[j].x)*(P[i].x-P[j].x)+ (P[i].y-P[j].y)*(P[i].y-P[j].y); if (ujtav>maxtav){ Ptavol.a=P[i]; Ptavol.b=P[j]; maxtav=ujtav; } }while(i!=i0 || j!=j0); 20

Ptavol.abtav=Math.sqrt(maxtav); return Ptavol; } }

9.8.

Metszo˝ szakaszpárok létezésének vizsgálata

Bemenet:

S = {s1 = p1 q1 , . . . sn = pn qn } Kimenet: ˝ i, j : 1 ≤ i < j ≤ n, a pi qi és p j q j szakasz metszo, 0, 0 ha nincs ilyen i, j pár. Sepro˝ egyenes Seprés során egy képzeletbeli sepro˝ egyenest mozgatunk a geometriai elemek halmazán. Azt a dimenziót, amelyben ˝ a sepro˝ egyenes halad, idodimenziónak hívjuk. Jelen esetben a sepro˝ egyenes az y-tengellyel párhuzamos egyenes, ˝ az idodimenzió az x-koordináta lesz. Egyszerusít ˝ o˝ feltételek: ˝ 1. Egyik bemeneti szakasz sem függoleges. 2. Nincs három olyan szakasz, amelyek egy pontban metszenék egymást. s = pq szakasz esetén : s.bal = p és s. jobb = q jelölést használjuk. A pontok koordinátáira pedig p.x és p.y

9.9.

Szakaszok rendezése

R

Legyen s1 és s2 szakasz és x ∈ Azt mondjuk, hogy s1 összehasonlítható s2 -vel x-nél, ha

s1 .bal.x ≤ x ≤ s1 . jobb.x ∧ s2 .bal.x ≤ x ≤ s2 . jobb.x 9.3. definíció. Az s1 szakasz felette van az s2 szakasznak, jelben s1 >x s2 , ha s1 összehasonlítható s2 -vel x-nél és az x sepero˝ egyenesnek s1 -el vett metszete magasabban van, mint s2 -el vett metszete. 9.4. Állítás. A >x reláció lineáris rendezési reláció 9.5. Állítás. Ha x1 < x2 -re s1 >x1 s2 és s2 >x2 s1 , akkor az s1 és s2 szakasz metszi egymást x1 és x2 között. Továbbá, ha x1 és x2 a sepro˝ egyenes két egymást követo˝ megállási helye, akkor x1 -ben a két szakasz egymást követo˝ lesz a rendezésben.



Bizonyítás. Az ábráról látható.

˝ ˝ megeloz ˝ o, ˝ és követo˝ szakasz metsziTehát elegendo˝ ellenorizni minden szakasz berakásakor, hogy a rendezésben ot ˝ ˝ o˝ és követo˝ szakaszok metszik-e egymást. e a berakottat, és kivételkor ellenorizni, hogy a kivett szakaszt megeloz

9.10.

A sepro˝ egyenes mozgatása

˝ ˝ 1. Esetpontok jegyzéke: azon idopontok (rendezett) sorozata, amely idopontokban a sepro˝ egyenes megáll. 2. A sepro˝ egyenes állapotleírása: az egyenes által metszett elemek rendezett halmaza. 21

x1

x2

x1

x2

19. ábra.

x 20. ábra. Az esetpontok jegyzéke azon x értékek halmaza, ahol a sepro˝ egyenes megáll.

22

S Esetpontok jegyzéke: = {s.bal.x : s ∈ S} {s. jobb.x : s ∈ S} Pontosabban: tegyük fel, hogy a szakaszok az S[1], . . . , S[n] felsorolással adottak. Feltételezzük, hogy S[i].bal.x <

S[i]. jobb.x VegP = {hS[i].bal.x,true, ii : i = 1, . . . , n}

[

{hS[i]. jobb.x, f alse, ii : i = 1, . . . , n}

˝ Rendezzük a VegP halmaz elemeit a sepro˝ egyenes haladásának megfeleloen, azaz a hx1, b1, i1i hármas akkor és ˝ csak akkor elozze meg az hx2, b2, i2i hármast, ha x1 < x2 vagy x1 = x2 és b1 = true és b2 = f alse vagy x1 = x2 és b1 = true és b2 = true és S[i1].bal.y < S[i2].bal.y vagy x1 = x2 és b1 = f alse és b2 = f alse és S[i1]. jobb.y < S[i2]. jobb.y Állapotleírás adott x-re legyen F az x-ben összehasonlítható szakaszok >x -szerint rendezett halmaza. A sepro˝ egyenes mozgatásakor, azaz a VegP szakaszvégpontok fenti rendezése szerint haladva: Ha a hx, b, ii hármas az aktuális elem, akkor Ha b = true, azaz x az i. szakasz bal-végpontja, akkor szúrjuk be az si szakaszt F -be. ˝ Ha b = f alse, azaz x az i. szakasz jobb-végpontja, akkor töröljük az si szakaszt F -bol. ˝ ˝ Beszúrást közvetlenül követoen határozzuk meg a beszúrt si szakasz követojét F -ben. Ha ez metszi si -t, akkor

si. jobb

si.bal s j. jobb sj

si

si sj

s j.bal s j. jobb

s j.bal

si. jobb

si.bal x

x 21. ábra.

s j .bal

si.bal

sj

si

si.bal

si. jobb

s j . jobb si si. jobb

sj s j .bal s j . jobb

x

x 22. ábra.

˝ ˝ ojét ˝ készen vagyunk. Hasonlóan, a beszúrást közvetlenül követoen határozzuk meg a beszúrt si szakasz megeloz F -ben. Ha ez metszi si -t, akkor készen vagyunk. 23

˝ oen ˝ ˝ o˝ s j1 és követo˝ s j2 szakaTörlés esetén a törlést megeloz határozzuk meg a törlendo˝ si szakaszt F -ben megeloz szokat. Ha mindketto˝ létezik és metszik egymást, akkor készen vagyunk. Tehát az alábbi muveletekre ˝ van szükség: B OVIT (F, I ) TOROL (F, I ) E LOZ (F, I ) KOVET (F, I ) Az RH ALMAZ adattípus mindezen muveleteket ˝ biztosítja. Megvalósítás. ˝ Ezek a muveletek ˝ hatékonyan megvalósíthatók kiegyensúlyozott keresovával, pl. AVL-fával, vagy piros-fekete fával. Ekkor minden muvelet ˝ futási ideje legrosszabb esetben O(lg n). ˝ Ekkor az algoritmus futási ideje legrosszabb esetben O(n lg n) lesz, mivel a VegP halmaz rendezheto˝ O(n lg n) idoben, ˝ továbbá az, hogy két szakasz metszi-e egymást O(1) idoben megállapítható. ˝ A kiegyensúlyozott bináris keresofában nem kulcs szerinti a rendezés. Az adatmezo˝ tartalmazza a szakasz sorszámát, ˝ S a szakaszok tömbje legyen globális az eljárásokra nézve. A keresofában a < összehasonlítás legyen a <x reláció:

public class SzakaszMetszKereso{ private static class SeproE implements Comparable<SeproE>{ /** A sepr˝ o egyenes megállási pontjainak típusa */ double x,y; int az; boolean bal; SeproE(double xx, double yy, boolean b, int a){ x=xx; y=yy; bal=b; az=a; } public int compareTo(SeproE e){ if (this.x==e.x&&this.bal==e.bal&&this.az==e.az) return 0; if (this.x<e.x || this.x==e.x && this.bal && !e.bal|| this.x==e.x && this.bal==e.bal && this.y<e.y ){ return -1; }else return 1; } } private static class FElem implements Comparable{ /** A Felett rendezési reláció megvalósítása */ public Szakasz[] S; int ind; public int compareTo(FElem e){ int fir; if (this.ind==e.ind) return 0; if (S[ind].bal.x<=e.S[e.ind].bal.x){ fir=Geom.ForgasIrany( S[ind].bal, S[ind].jobb, e.S[e.ind].bal); }else{ fir=-Geom.ForgasIrany( 24

e.S[e.ind].bal,e.S[e.ind].jobb,S[ind].bal); } return (fir<0||fir==0&&ind<e.ind)?-1:1; } FElem(Szakasz[] q, int az){ S=q; ind=az;} FElem(){} } public static Szakasz[] Keres(Szakasz[] S){ Szakasz[] MetszoPar=new Szakasz[2]; //az két metsz˝ o szakasz int n=S.length; SeproE[] VegP=new SeproE[2*n];//a sepr˝ o egyenes megállási pontjai for (int i=0; i F=new RHalmazFa("PF"); FElem p, q; FElem t=new FElem(); for (int ii=0; ii<2*n; ii++){ int i=VegP[ii].az; if (VegP[ii].bal){ FElem e=new FElem(S,i); F.Bovit(e); p=F.Elozo(e); if (p!=null && Geom.SzakaszParMetsz(S[i],S[p.ind]) ){ MetszoPar[0]=S[i]; MetszoPar[1]=S[p.ind]; break; } p=F.Koveto(e); if (p!=null && Geom.SzakaszParMetsz(S[i],S[p.ind]) ){ MetszoPar[0]=S[i]; MetszoPar[1]=S[p.ind]; break; } }else{ t.S=S; t.ind=i; p=F.Elozo(t); q=F.Koveto(t); if (p!=null&&q!=null&& Geom.SzakaszParMetsz(S[p.ind],S[q.ind])){ MetszoPar[0]=S[p.ind]; MetszoPar[1]=S[q.ind]; break; } F.Torol(t); } } return MetszoPar; } } 25

9.11.

Legközelebbi pontpár megkeresése p

Legyen p és q a síkon két pont. A két pont távolsága az Euklideszi távolság, azaz tav(p, q) = (p.x − q.x)2 + (p.y − q.y)2 . Bemenet: P = {p1 , . . . pn } ponthalmaz Kimenet: i, j : 1 ≤ i < j ≤ n, a tav(pi , p j ) minimális. Oszd-meg-és-uralkodj elvu˝ algoritmus. Legyen S a pontok (azonosítóinak) halmaza, X a pontok (azonosítóinak) x-koordináta szerint rendezett sorozata, Y pedig pontok (azonosítóinak) y-koordináta szerint rendezett sorozata. Elvi algoritmus: Bemenet: S, X,Y Kimenet: d min. távolság, a, b két legközelebbi pont; tav(a, b) = d

TAV K ERES (S,X,Y, D, A , B ) begin {TavKeres} if |S| ≤ 3 then Begin ˝ minden pontpárra ellenorizzük a távolságot és vegyük a legkisebbet; Exit; end; SL := S-nek d|S|/2e számú eleme x-koordináta szerint; SR := S-nek b|S|/2c számú eleme x-koordináta szerint; ˝ x-kootdináta érték; x0 := a felosztó (felezo) XL := SL elemeinek x-koordináta szerint rendezett sorozata; XR := SR elemeinek x-koordináta szerint rendezett sorozata; TAV K ERES(SL , XL ,YL , dL , aL , bL ); TAV K ERES(SR , XR ,YR , dR , aR , bR ); d := min(dL , dR ); Y d := azon S-beli pontok halmaza, amelyek x-koordinátájára |x0 − x| ≤ d ; Y d legyen y-koordináta szerint rendezett; Ha van Y d -ben d -nél közelebbi pár, akkor azt adjuk vissza, egyébként d -t; end {TavKeres}

Állítás. Y d -ben elég minden p pontra csak p-t követo˝ 7 pontra nézni a távolságot, hogy találjuk d -nél közelebbi pontpárt, ha létezik ilyen. Futási ido˝ legrosszabb esetben.

T (n) = 2 T (n/2) + O(n) Tehát T (n) = (n lg n) Megvalósítás

public class LKozelPontpar{ private static class XKoord implements Comparator{ public int compare(Pont p1, Pont p2 ){ return (p1.x
                                   pL 

 



pR

δ

δ

SL



SR

l

23. ábra. A sik (tartomány) két részre osztása az l egyenessel.



                         

   

Itt két pont is lehet,

δ



egy SL -ben, egySR -ben







δ SL

δ l



SR

˝ u˝ sávban adott p ponthoz legfeljebb 7 olyan pont lehet, amelynek p-tol ˝ vett távolsága legfeljebb 24. ábra. A δ átméroj ˝ δ. Ezek a pontok a y-koordináta szerinti rendezésben egymást követok.

27

private static class YKoord implements Comparator{ public int compare(Pont p1, Pont p2 ){ return (p1.y>1; int zbal = bal, // kurzor Z[bal:kozep]-hez zjobb = kozep+1; // kurzor Z[kozep+1:jobb]-hez for (int i = bal; i <= jobb; i++) if (Y[i].az <= kozep) Z[zbal++] = Y[i]; else Z[zjobb++] = Y[i]; // uralkodj PontPar balkozel = ParKeres(X, Z, Y, bal, kozep); PontPar jobbkozel = ParKeres(X, Z, Y, kozep+1, jobb); PontPar kozel; kozel= (balkozel.abtav<jobbkozel.abtav)? balkozel : jobbkozel; // Y rekonstruálása: Z[bal:kozep], Z[bal+1,jobb]->Y[bal:jobb] int k=bal; {int i=bal; int j=kozep+1; while (i<=kozep && j<=jobb) //összefésülés if (Z[i].y
28

for (int i = bal; i <= jobb; i++) if (Math.abs(X[kozep].x - Y[i].x) < kozel.abtav) Z[k++] = Y[i]; for (int i = bal; i < k-1; i++) for (int j=i+1; j
29

Related Documents

N9
June 2020 5
N9
December 2019 18
Bi1(n9)
October 2019 8
Math1(n9)
October 2019 12
Bi2(n9)
October 2019 13
Bm2(n9)
October 2019 27