9. Geometriai algoritmusok

Hasonló dokumentumok
Algoritmusok és adatszerkezetek II.

Geometriai algoritmusok

Geometriai algoritmusok

Geometriai algoritmusok

Geometriai algoritmusok. pont helyzete, konvex burok, ponthalmaz legközelebbi és legtávolabbi pontpárja, metsző szakaszpárok keresése

Algoritmizálás, adatmodellezés 10. előadás

17. előadás: Vektorok a térben

Algoritmusok és adatszerkezetek II.

Algoritmusok és adatszerkezetek II.

Számláló rendezés. Példa

Specifikáció. B logikai formula, a bemeneti feltétel, K logikai formula, a kimeneti feltétel, A az algoritmus, amelyre az állítás vonatkozik.

Koordináta-geometria feladatok (emelt szint)

14. Mediánok és rendezett minták

Geometriai algoritmusok

2. Rekurzió. = 2P2(n,n) 2 < 2P2(n,n) 1

Adatszerkezetek I. 10. előadás

Algoritmizálás. Horváth Gyula Szegedi Tudományegyetem Természettudományi és Informatikai Kar

GEOMETRIA 1, alapszint

Specifikáció. B logikai formula, a bemeneti feltétel, K logikai formula, a kimeneti feltétel, A az algoritmus, amelyre az állítás vonatkozik.

Bánsághi Anna 2014 Bánsághi Anna 1 of 68

Edényrendezés. Futási idő: Tegyük fel, hogy m = n, ekkor: legjobb eset Θ(n), legrosszabb eset Θ(n 2 ), átlagos eset Θ(n).

8. Mohó algoritmusok Egy esemény-kiválasztási probléma. Az esemény-kiválasztási probléma optimális részproblémák szerkezete

Algoritmusok helyességének bizonyítása. A Floyd-módszer

Függvények Megoldások

Számjegyes vagy radix rendezés

A számítástudomány alapjai. Katona Gyula Y. Számítástudományi és Információelméleti Tanszék Budapesti Műszaki és Gazdaságtudományi Egyetem

Nagy András. Feladatok a koordináta-geometria, egyenesek témaköréhez 11. osztály 2010.

GEOMETRIAI FELADATOK 1. (ESETTANULMÁNY)

1. Alapfogalmak Algoritmus Számítási probléma Specifikáció Algoritmusok futási ideje

10. előadás. Konvex halmazok

A félév során előkerülő témakörök

9. Írjuk fel annak a síknak az egyenletét, amely átmegy az M 0(1, 2, 3) ponton és. egyenessel;

1. ábra. Számláló rendezés

b) Ábrázolja ugyanabban a koordinátarendszerben a g függvényt! (2 pont) c) Oldja meg az ( x ) 2

Mindent olyan egyszerűvé kell tenni, amennyire csak lehet, de nem egyszerűbbé.

Gráfok, definíciók. Gráfok ábrázolása. Az adott probléma megoldásához ténylegesen mely műveletek szükségesek. Ábrázolások. Példa:

= Y y 0. = Z z 0. u 1. = Z z 1 z 2 z 1. = Y y 1 y 2 y 1

Brósch Zoltán (Debreceni Egyetem Kossuth Lajos Gyakorló Gimnáziuma) Megoldások

Minimális feszítőfák Legyen G = (V,E,c), c : E R + egy súlyozott irányítatlan gráf. Terjesszük ki a súlyfüggvényt a T E élhalmazokra:

MATEMATIKA ÉRETTSÉGI TÍPUSFELADATOK MEGOLDÁSAI KÖZÉPSZINT Függvények

MATEMATIKA ÉRETTSÉGI TÍPUSFELADATOK KÖZÉPSZINT Függvények

Keresés és rendezés. A programozás alapjai I. Hálózati Rendszerek és Szolgáltatások Tanszék Farkas Balázs, Fiala Péter, Vitéz András, Zsóka Zoltán

Mindent olyan egyszerűvé kell tenni, amennyire csak lehet, de nem egyszerűbbé. (Albert Einstein) Halmazok 1

Koordináta-geometria II.

Elmaradó óra. Az F = (V,T) gráf minimális feszitőfája G-nek, ha. F feszitőfája G-nek, és. C(T) minimális

2. ELŐADÁS. Transzformációk Egyszerű alakzatok

Információ megjelenítés Számítógépes ábrázolás. Dr. Iványi Péter

Oktatási Hivatal. 1 pont. A feltételek alapján felírhatók az. összevonás után az. 1 pont

Adatszerkezetek. Nevezetes algoritmusok (Keresések, rendezések)

Algoritmusok és adatszerkezetek II.

10. Gráf absztrakt adattípus, gráfok ábrázolása

Az egyenes és a sík analitikus geometriája

INFORMATIKA javítókulcs 2016

Tartalom Keresés és rendezés. Vektoralgoritmusok. 1. fejezet. Keresés adatvektorban. A programozás alapjai I.

Brósch Zoltán (Debreceni Egyetem Kossuth Lajos Gyakorló Gimnáziuma) Megoldások

ARCHIMEDES MATEMATIKA VERSENY

... fi. ... fk. 6. Fabejáró algoritmusok Rekurzív preorder bejárás (elsőfiú-testvér ábrázolásra)

Koordinátageometria. , azaz ( ) a B halmazt pontosan azok a pontok alkotják, amelynek koordinátáira:

Felvételi vizsga mintatételsor Informatika írásbeli vizsga

Brósch Zoltán (Debreceni Egyetem Kossuth Lajos Gyakorló Gimnáziuma) Megoldások

MATEMATIKA ÉRETTSÉGI TÍPUSFELADATOK MEGOLDÁSAI KÖZÉP SZINT Függvények

Minimum követelmények matematika tantárgyból 11. évfolyamon

Algoritmuselmélet 2. előadás

Összeállította: dr. Leitold Adrien egyetemi docens

Önszervező bináris keresőfák

5. házi feladat. AB, CD kitér élpárra történ tükrözések: Az ered transzformáció: mivel az origó xpont, így nincs szükség homogénkoordinátás

Módosítható Prioritási sor Binomiális kupaccal. Wednesday, March 21, 12

Amortizációs költségelemzés

Algoritmusok és adatszerkezetek gyakorlat 07

Egyenes és sík. Wettl Ferenc szeptember 29. Wettl Ferenc () Egyenes és sík szeptember / 15

MATEMATIKA ÉRETTSÉGI TÍPUSFELADATOK MEGOLDÁSAI KÖZÉPSZINT Függvények

Cohen-Sutherland vágóalgoritmus

8. előadás. Kúpszeletek

Intergrált Intenzív Matematika Érettségi

Érdekes informatika feladatok

Vektorok és koordinátageometria

A 2017/2018 tanévi Országos Középiskolai Tanulmányi Verseny második fordulójának feladatai. INFORMATIKA II. (programozás) kategória

Algoritmusok bonyolultsága

MATEMATIKA ÉRETTSÉGI TÍPUSFELADATOK KÖZÉP SZINT Függvények

Matematika A1a Analízis

Matematika 11 Koordináta geometria. matematika és fizika szakos középiskolai tanár. > o < szeptember 27.

Adatszerkezet - műveletek

Az egyenlőtlenség mindkét oldalát szorozzuk meg 4 16-al:

KOORDINÁTA-GEOMETRIA

NULLADIK MATEMATIKA ZÁRTHELYI

Tuesday, March 6, 12. Hasító táblázatok

HALMAZOK TULAJDONSÁGAI,

Koordinátageometriai gyakorló feladatok I ( vektorok )

Síkbeli egyenesek. 2. Egy egyenes az x = 1 4t, y = 2 + t parméteres egyenletekkel adott. Határozzuk meg

Lengyelné Dr. Szilágyi Szilvia április 7.

Gyakorló feladatok. 2. Matematikai indukcióval bizonyítsuk be, hogy n N : 5 2 4n n (n + 1) 2 n (n + 1) (2n + 1) 6

NULLADIK MATEMATIKA ZÁRTHELYI

Háromszögek, négyszögek, sokszögek 9. évfolyam

4. Fuzzy relációk. Gépi intelligencia I. Fodor János NIMGI1MIEM BMF NIK IMRI

3. Fuzzy aritmetika. Gépi intelligencia I. Fodor János NIMGI1MIEM BMF NIK IMRI

Lineáris algebra mérnököknek

Követelmény a 6. évfolyamon félévkor matematikából

BBTE Matek-Infó verseny mintatételsor Informatika írásbeli vizsga

Felvételi tematika INFORMATIKA

Analitikus térgeometria

Átírás:

9. Geometriai algoritmusok Számos olyan gyakorlati számítási probléma van, amely megoldható olyan geometriai modellben, amelyben csak egyszerű objektumok, pontok, egyenesek, szakaszok, szögek, szögtartományok, poligonok szerepelnek. Ilyen alapvető feladatokat vizsgálunk. 9.1. Alapfogalmak Pont: (x,y) R R Szakasz Legyen p 1, p 2 pont. A p 1 és p 2 pont által meghatározott szakasz: p 1 p 2 = {p = (x,y) : x = α p 1.x + (1 α)p 2.x, y = α p 1.y + (1 α) p 2.y), α R, 0 α 1 Ha p 1 és p 2 sorrendje számít, akkor irányított szakaszról beszélünk, jele: p 1 p 2. Egyenes Egyenes megadása: 1. y = m x + b egyenlettel: azon (x, y) pontok halmaza, amelyekre teljesül az egyenlet. 2. ax + by + c = 0 egyenlettel. 3. Egyenes megadása két pontjával: e(p 1, p 2 ) 9.2. Feladat: Pontok összekötése zárt, nem-metsző 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 metsző szakaszpár. Egy ilyen zárt, nem-metsző poligon megadható a pontok azonosítóinak egy felsorolásával: a felsorolásban egymást követő pontokat kötjük össze egyenes szakaszokkal, továbbá, az utolsót az elsővel is összekötjük. Bemeneti specifikáció A poligon.be szöveges állomány első 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-metsző poligont leíró sorozatot kell kiírni. 1

Példa bemenet és kimenet poligon.be 6 2 0 1 4 0 2 3 2 2 4 2 6 poligon.ki 3 1 4 5 6 2 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 (előjeles) szög alapján. Rendezzük a pontokat úgy, hogy a Q sarokpont legyen az első, és p i előbb legyen mint p j akkor és csak akkor, ha p i φ(q, p i ) Q Q φ(q, p i ) p i 1. ábra. A p i ponthoz tartozó előjeles szög: φ(q, p i ). A φ(q, p i ) < φ(q, p j ), vagy φ(q, p i ) = φ(q, p j ) és p i közelebb van Q-hoz, azaz p i.x < p j.x, vagy φ(q, p i ) = φ(q, p j ) és p i.x = p j.x és p i.y < p j.y. Ha ebben a sorrendben kötjük össze a pontokat, kivéve, hogy az utolsó egyenesen lévő pontokat fordított sorrendben vesszük, akkor egy zárt, nem metsző poligont kapunk. Hogyan dönthető el, hogy φ(q, p i ) < φ(q, p j )? Minden i > 1-re π 2 < φ(q, p i) π 2 és ebben a tartományban a tangens függvény szigorúan monoton növekvő, tehát φ(q, p i ) < φ(q, p j ) akkor és csak akkor, ha tan(φ(q, p i )) = p i.y Q.y p i.x Q.x < p j.y Q.y p j.x Q.x = tan(φ(q, p j)) Mivel Q sarokpont, így p i.x Q.x 0 és p j.x Q.x 0, tehát akkor és csak akkor, ha φ(q, p i ) < φ(q, p j ) (p i.y q.y)(p j.x Q.x) < (p j.y Q.y)(p i.x Q.x) 2

p j p i p j.y Q.y p i.y Q.y Q p j.x Q.x p i.x Q.x 2. ábra. A φ(q, p i ) és φ(q, p j ) szögek viszonya. Tehát a pontok rendezése: p i megelőzi p j -t akkor és csak akkor, ha (p i.y Q.y)(p j.x Q.x) < (p j.y Q.y)(p i.x Q.x) (1) (p i.y Q.y)(p j.x Q.x) = (p j.y Q.y)(p i.x Q.x) p i.x < p j.x (2) (p i.y Q.y)(p j.x Q.x) = (p j.y Q.y)(p i.x Q.x) p i.x = p j.x p i.y < p j.y (3) A sík pontjainak ábrázolására a PONT 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 SAROKRENDEZ eljárásunk, amely a P ponthalmazt rendezi a bal-alsó sarokpontjára vonatkozó polárszög szerint. Ekkor a feladat megoldása a következőké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<n; i++) S[i]=P[i].az; int i=n-2; while ( (P[n-1].y-P[0].y)*(P[i].x-P[0].x)== (P[i].y-P[0].y)*(P[n-1].x-P[0].x) ) i--; 3

//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 SAROKRENDEZ eljárás a kupacrendezést használva rendezi a ponthalmazt. A RENDEZ.KUPACREND1 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 static void SarokRendez(Pont[] P){ int mi=0; int n=p.length; for (int i=1; i<n; i++) //bal-also sarokpont meghatározása if (P[i].x<P[mi].x P[i].x==P[mi].x && P[i].y<P[mi].y) mi=i; Pont x=p[0]; //a sarokpont kicserélése P[0]=P[mi]; P[mi]=x; //P[0]-al SarokRend r=new SarokRend(P[0]); //a rendezési reláció létesítése Rendez.KupacRend1(P, r); //P[1..n-1] rendezése kupacrendezéssel 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<n; i++){ int x=bef.nextint(); int y=bef.nextint(); bef.nextline(); P[i]=new Pont(x,y,i+1); bef.close(); return P; 4

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 előfordul, hogy a síkon adott p 1 és p 2 pontra el kell dönteni, hogy a p 1 ponthoz képest a p 2 pont milyen forgásirányba esik. Tekintsük a 3. ábrán látható p 1 és p 2 vektorokat. A p 1 p 2 keresztszorzat a (0,0), p 1, p 2 és a p 1 + p 2 = (p 1.x + p 2.x, p 1.y + p 2.y) pontok által alkotott paralelogramma előjeles területeként értelmezhető. x 2 x 1 p 1 + p 2 y 1 p 2 y 2 y 2 p1 y 1 (0,0) x 1 x 2 3. ábra. A paralelogramma előjeles területe: T = (x 1 + x 2 )(y 1 + y 2 ) x 1 y 1 x 2 y 2 x 2 y 1 x 2 y 1 = x 1 y 1 + x 1 y 2 + x 2 y 1 + x 2 y 2 x 1 y 1 x 2 y 2 x 2 y 1 x 2 y 1 = x 1 y 2 x 2 y 1 p 1 p 2 = ( x1 x det 2 y 1 y 2 = x 1 y 2 x 2 y 1 = p 2 p 1. ) p 1 p 2 > 0 p 2 az órajárással ellentétes irányban van p 1 -hez képest. p 1 p 2 = 0 a (0,0), p 1 és p 2 pontok egy egyenesre esnek (kollineárisak). p 1 p 2 < 0 p 2 az órajárás irányban van p 1 -hez képest. Még általánosabban, adott két csatlakozó irányított szakasz, p 0 p 1 és p 1 p 2, milyen irányba fordul p 1 p 2 a p 0 p 1 -hez viszonyítva? A válasz (p 1 p 0 ) (p 2 p 0 ) = (p 1.x p 0.x)(p 2.y p 0.y) (p 2.x p 0.x)(p 1.y p 0.y) keresztszorzat előjele alapján megadható. 5

y p 1 + p 2 y p 2 p (0,0) x p 1 (0,0) (a) x (b) 4. ábra. (a) A p 1 és p 2 vektorok keresztszorzata a paralelogramma előjeles területe. (b) A világos tartomány azokat a pontokat tartalmazza, amelyek a p-től órajárással egyező irányba esnek, a sötétebb pedig azokat, amelyek órajárással ellentétes irányba esnek p-től. p2 p2 p1 p1 p0 p0 5. ábra. Csatlakozó szakaszok forgásiránya. 6

(p 1 p 0 ) (p 2 p 0 ) > 0 : p 1 p 2 balra fordul, (p 1 p 0 ) (p 2 p 0 ) = 0 : p 0 p 1 és p 1 p 2 kollineárisak, (p 1 p 0 ) (p 2 p 0 ) < 0 : p 1 p 2 jobbra fordul. 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 p 0, p 1, p 2 pontok esetén p 1 közelebb van-e p 0 -hoz, mint p 2 : max(p1.y,p2.y) q.y q p1 min(p1.y,p2.y) p2 min(p1.x,p2.x) q.x max(p1.x,p2.x) 6. ábra. A q pont a p 1 p 2 szakaszra esik, ha p 1, p 2 és q kollineárisak és min(p 1.x, p 2.x) q.x max(p 1.x, p 2.x) és min(p 1.y, p 2.y) q.y max(p 1.y, p 2.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 FORGASIRANY é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>{ 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, tetszőleges q pontra vonatkozó polárszög szerinti rendezés rendezési relációja is megadható a FOR- GASIRANY és a KOZTE felhasználásával. 13 11 14 12 2 3 1 q 9 10 7 4 5 6 8 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<Pont>{ 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-metsző poligon a csúcsainak p 1,..., p n órajárással ellentétes felsorolásával és adott egy q pont. Eldöntendő a q pontnak a poligonhoz képesti helyzete, azaz, hogy a belsejéhez tartozik-e, az oldalán van-e, avagy külső pont? Megoldás Válasszunk egy olyan q 0 pontot, amely biztosan nem tartozik a poligon belsejéhez és a poligon egyetlen csúcsa sem esik a q 0 q szakaszra, legfeljebb ha q megegyezik valamelyik csúccsal. (Van ilyen pont.) Ha a q 0 q szakasz a poligon páratlan számú oldalát metszi, akkor q belső pont, egyébként külső. A q 0 külső pont q q0 8. ábra. A q 0 q szakasz a poligon páratlan sok oldalát metszi, tehát belső pont. választása. Legyen q 0.y = max{p i.y p i.y < q.y,i = 1,...n és q 0.x = min{p i.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ülső pont. A q0 pont ilyen választása esetén legfeljebb a q pont esik a poligon valamelyik oldalára, amikor is q nem belső pont lesz. Ezt az esetet külön ellenőrizzük. Egyébként, a poligon bármely p i p i+1 oldalának akkor és csak akkor van közös pontja a q 0 q szakasszal, ha p i és p i+1 az e(q 0,q) egyenes különböző oldalára esik és a q 0 és q pont az e(p i, p i+1 ) egyenes különböző oldalára esik. Ez a feltétel a FORGÁSIRANY eljárás felhasználásával egyszerűen 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 q 0 q szakaszra esik. q q0 10. ábra. A q 0 pont választása:q 0.y = max{p i.y p i.y < q.y,i = 1,...n és q 0.x = min{p i.x i = 1,...n 1. max(p1.y,p2.y) q.y q p1 min(p1.y,p2.y) p2 min(p1.x,p2.x) q.x max(p1.x,p2.x) 11. ábra. A q pont a p 1 p 2 szakaszra esik, ha p 1, p 2 és q kollineárisak és q.x p 1.x p2.x p1.x és q.x p 2.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; i<n; i++){ if (P[i].y<q.y && (P[i].y>y0 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<n; i++){ int ii=(i<n-1)? i+1: 0; if (Szakaszon(P[i], P[ii], q) ) return 0; if (ForgasIrany(P[i],P[ii],q0)*ForgasIrany(P[i],P[ii],q)<0 && ForgasIrany(q0, q, P[i])*ForgasIrany(q0, q, P[ii]) <0 ) metsz++; return (metsz % 2==1)? -1:1; A algoritmus futási ideje legrosszabb esetben is a poligon csúcsainak n számával arányos, tehát O(n). 9.4. Metsző szakaszpárok Eldöntendő, hogy metszi-e egymást adott p 1 p 2 és q 1 q 2 szakasz? 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

q2 p2 p2 p2 q1 q1 q2 p1 p1 q2 p1 q1 p2 p1 q2 q2 p1 q1 p2 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 Definíció. Egy egyszerű (nem metsző) poligon konvex, ha bármely két belső pontját összekötő szakasz minden pontja a poligon belsejében, vagy határán van. Definíció. Egy P = {p 1,..., p n ponthalmaz konvex burka az a legszűkebb Q konvex poligon, amely a ponthalmaz minden pontját tartalmazza. Megoldás Graham-féle pásztázással Első 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 q 1,...,q m az így kapott pontsorozat polárszög szerinti rendezésben. Mindaddig, amíg van három olyan cirkulárisan egymást követő q i, q i+1 q i+2 pont, hogy q i+1 q i+2 jobbra fordul q i q i+1 -hez képest, hagyjuk el a q i+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 lgn). /** *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; i<n; i++){ while (m>0 && 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. Érintő egyenes keresése lineáris időben 9.1. definíció. Legyen P ponthalmaz, a P és q egy pont. Azt mondjuk, hogy az e(q,a) a P ponthalmaz jobboldali érintő (támasztó) egyenese, ha P minden pontja qa-tól nem jobbra van. Hasonlóan, az e(q,a) a P ponthalmaz baloldali érintő (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 érintő egyenese. Nyilvánvaló, hogy akkor és csak akkor létezik adott q ponton átmenő érintő egyenes, ha q a P ponthalmaz konvex burkán kivül, vagy az oldalán van. Feladat: érintő 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 érintő 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 (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ő 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<n&&geom.forgasirany(q,a,p[i])==0; i++) if (i==n){//p pontjai egy egyenesre esnek return abc; b=p[i]; if (Geom.ForgasIrany(q,a,b)<0){//q-a-tól b balra essen a=b; b=p[0]; for (int j=1; j<n; j++){ firqa=geom.forgasirany(q,a,p[j]); firqb=geom.forgasirany(q,b,p[j]); if (firqa<0 && firqb>=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ő 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<n; i++) if (P[i].az!=a.az && P[i].az!=b.az && P[i].az!=c.az && Geom.ForgasIrany(a,b,P[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 = {p 1,..., p n ponthalmaz. Határozzuk meg a ponthalmaz egy legtávolabbi pontpárját! Megoldás. A naiv algoritmus, amely minden pontpárra kiszámítja azok távolságát, futási ideje O( n 1 n(n 1) i=1 i) = 2 = O(n 2 ). Konvex burok alkalmazásával O(n lg n) idejű 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 p i és p j pontpár, hogy ha van olyan p i -n és p j -n átmenő 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 = p 1,..., p m a konvex poligon csúcspontjainak órajárással ellentétes felsorolása. Legyen p i a konvex poligon legkisebb y-koordinátájú pontja, ha kettő 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 kettő ilyen van, akkor ezek közül válasszuk a legkisebb x-koordinátájút. p i és p j nyilvánvalóan átellenes pontjai a poligonnak. Az összes átellenes pontpár lineáris időben meghatározható görgetéssel. Ha az e(p i, p i+1 ) egyenes hajlásszöge p j p j+1 p i+1 p i 18. ábra. Görgetés kisebb, mint az e(p j, p j+1 ) egyenes hajlásszöge, akkor a p i+1 és p j is átellenes pontpár lesz, egyébként a p i p j+1 lesz átellenes pontpár. (a +1 modulo m értendő). Forgassuk el balra a 14.ábrán látható p i és p j pontokon átmenő párhuzamos egyeneseket amíg valamelyik a p i p i+1 vagy a p j p j+1 oldalra nem ér. Ha előbb érjük el a p i p i+1 oldalt, 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önthető a következő kifejezéssel: FORGASIRANY(p j+1, p i+1 p i + p j+1, p j ) > 0 Következmény n elemű ponthalmaz egy legtávolabbi pontpárja O(n lg n) idejű algoritmussal kiszámítható. Következmény n elemű ponthalmaz vastagsága O(n lg n) idejű 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].y<P[i0].y (P[k].y==P[i0].y&&P[k].x>P[i0].x))i0=k; if (P[k].y>P[j0].y (P[k].y==P[j0].y&&P[k].x<P[j0].x))j0=k; double maxtav=(p[i0].x-p[j0].x)*(p[i0].x-p[j0].x)+ (P[i0].y-P[j0].y)*(P[i0].y-P[j0].y); PontPar Ptavol=new PontPar(P[i0], P[j0], maxtav); double ujtav; i=i0; j=j0; do{ //görgetés ii=(i+1)%m; jj=(j+1)%m; irany=geom.forgasirany(p[jj],eltol(p[jj],p[i],p[ii]),p[j]); if (irany>0){ 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]; while(i!=i0 j!=j0); maxtav=ujtav; 20

Ptavol.abtav=Math.sqrt(maxtav); return Ptavol; 9.8. Metsző szakaszpárok létezésének vizsgálata Bemenet: S = {s 1 = p 1 q 1,...s n = p n q n Kimenet: i, j : 1 i < j n, a p i q i és p j q j szakasz metsző, 0,0 ha nincs ilyen i, j pár. Seprő egyenes Seprés során egy képzeletbeli seprő egyenest mozgatunk a geometriai elemek halmazán. Azt a dimenziót, amelyben a seprő egyenes halad, idődimenziónak hívjuk. Jelen esetben a seprő egyenes az y-tengellyel párhuzamos egyenes, az idődimenzió az x-koordináta lesz. Egyszerűsítő feltételek: 1. Egyik bemeneti szakasz sem függőleges. 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 Legyen s 1 és s 2 szakasz és x R Azt mondjuk, hogy s 1 összehasonlítható s 2 -vel x-nél, ha s 1.bal.x x s 1. jobb.x s 2.bal.x x s 2. jobb.x 9.3. definíció. Az s 1 szakasz felette van az s 2 szakasznak, jelben s 1 > x s 2, ha s 1 összehasonlítható s 2 -vel x-nél és az x seperő egyenesnek s 1 -el vett metszete magasabban van, mint s 2 -el vett metszete. 9.4. Állítás. A > x reláció lineáris rendezési reláció 9.5. Állítás. Ha x 1 < x 2 -re s 1 > x1 s 2 és s 2 > x2 s 1, akkor az s 1 és s 2 szakasz metszi egymást x 1 és x 2 között. Továbbá, ha x 1 és x 2 a seprő egyenes két egymást követő megállási helye, akkor x 1 -ben a két szakasz egymást követő lesz a rendezésben. Bizonyítás. Az ábráról látható. Tehát elegendő ellenőrizni minden szakasz berakásakor, hogy a rendezésben őt megelőző, és követő szakasz metszie a berakottat, és kivételkor ellenőrizni, hogy a kivett szakaszt megelőző és követő szakaszok metszik-e egymást. 9.10. A seprő egyenes mozgatása 1. Esetpontok jegyzéke: azon időpontok (rendezett) sorozata, amely időpontokban a seprő egyenes megáll. 2. A seprő egyenes állapotleírása: az egyenes által metszett elemek rendezett halmaza. 21

x1 x2 x1 x2 19. ábra. 20. ábra. Az esetpontok jegyzéke azon x értékek halmaza, ahol a seprő egyenes megáll. x 22

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 = { S[i].bal.x,true,i : i = 1,...,n { S[i]. jobb.x, f alse,i : i = 1,...,n Rendezzük a VegP halmaz elemeit a seprő egyenes haladásának megfelelően, azaz a x1, b1, i1 hármas akkor és csak akkor előzze meg az x2,b2,i2 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 seprő egyenes mozgatásakor, azaz a VegP szakaszvégpontok fenti rendezése szerint haladva: Ha a x,b,i hármas az aktuális elem, akkor Ha b = true, azaz x az i. szakasz bal-végpontja, akkor szúrjuk be az s i szakaszt F-be. Ha b = f alse, azaz x az i. szakasz jobb-végpontja, akkor töröljük az s i szakaszt F-ből. Beszúrást közvetlenül követően határozzuk meg a beszúrt s i szakasz követőjét F-ben. Ha ez metszi s i -t, akkor si. jobb si.bal s j s j. jobb si s j s j.bal s j. jobb s j.bal si si. jobb si.bal x x 21. ábra. s j.bal s i.bal s j s i s i. jobb s i.bal s j si s i. jobb s j. jobb s j.bal s j. jobb x x 22. ábra. készen vagyunk. Hasonlóan, a beszúrást közvetlenül követően határozzuk meg a beszúrt s i szakasz megelőzőjét F-ben. Ha ez metszi s i -t, akkor készen vagyunk. 23

Törlés esetén a törlést megelőzően határozzuk meg a törlendő s i szakaszt F-ben megelőző s j1 és követő s j2 szakaszokat. Ha mindkettő létezik és metszik egymást, akkor készen vagyunk. Tehát az alábbi műveletekre van szükség: BOVIT(F,I) TOROL(F,I) ELOZ(F,I) KOVET(F,I) Az RHALMAZ adattípus mindezen műveleteket biztosítja. Megvalósítás. Ezek a műveletek hatékonyan megvalósíthatók kiegyensúlyozott keresővával, pl. AVL-fával, vagy piros-fekete fával. Ekkor minden művelet 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 rendezhető O(n lg n) időben, továbbá az, hogy két szakasz metszi-e egymást O(1) időben megállapítható. A kiegyensúlyozott bináris keresőfában nem kulcs szerinti a rendezés. Az adatmező tartalmazza a szakasz sorszámát, S a szakaszok tömbje legyen globális az eljárásokra nézve. A keresőfában a < összehasonlítás legyen a < x reláció: public class SzakaszMetszKereso{ private static class SeproE implements Comparable<SeproE>{ /** A seprő 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<FElem>{ /** 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ő szakasz int n=s.length; SeproE[] VegP=new SeproE[2*n];//a seprő egyenes megállási pontjai for (int i=0; i<n; i++){ VegP[i]=new SeproE(S[i].bal.x, S[i].bal.y,true,S[i].az); VegP[n+i]=new SeproE(S[i].jobb.x,S[i].jobb.y,false,S[i].az); Rendez.KupacRend(VegP); RHalmaz<FElem> F=new RHalmazFa<FElem>("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 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 = {p 1,... p n ponthalmaz Kimenet: i, j : 1 i < j n, a tav(p i, p j ) minimális. Oszd-meg-és-uralkodj elvű 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 TAVKERES(S,X,Y, D, A,B) begin {TavKeres if S 3 then Begin minden pontpárra ellenőrizzük a távolságot és vegyük a legkisebbet; Exit; end; S L := S-nek S /2 számú eleme x-koordináta szerint; S R := S-nek S /2 számú eleme x-koordináta szerint; x 0 := a felosztó (felező) x-kootdináta érték; X L := S L elemeinek x-koordináta szerint rendezett sorozata; X R := S R elemeinek x-koordináta szerint rendezett sorozata; TAVKERES(S L,X L,Y L,d L,a L,b L ); TAVKERES(S R,X R,Y R,d R,a R,b R ); d := min(d L,d R ); Y d := azon S-beli pontok halmaza, amelyek x-koordinátájára x 0 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övető 7 pontra nézni a távolságot, hogy találjuk d-nél közelebbi pontpárt, ha létezik ilyen. Futási idő legrosszabb esetben. T (n) = 2T (n/2) + O(n) Tehát T (n) = (n lgn) Megvalósítás public class LKozelPontpar{ private static class XKoord implements Comparator<Pont>{ public int compare(pont p1, Pont p2 ){ return (p1.x<p2.x p1.x==p2.x && p1.az<p2.az)? -1:1; 26

p L p R δ S L l δ S R 23. ábra. A sik (tartomány) két részre osztása az l egyenessel. δ Itt két pont is lehet, egy S L -ben, egys R -ben δ S L l δ S R 24. ábra. A δ átmérőjű sávban adott p ponthoz legfeljebb 7 olyan pont lehet, amelynek p-től vett távolsága legfeljebb δ. Ezek a pontok a y-koordináta szerinti rendezésben egymást követők. 27

private static class YKoord implements Comparator<Pont>{ public int compare(pont p1, Pont p2 ){ return (p1.y<p2.y p1.y==p2.y && p1.az<p2.az)? -1:1; public static PontPar ParKeres( Pont[] X, Pont[] Y, Pont[] Z, int bal, int jobb){ if (jobb-bal == 1) // csak két pont van return new PontPar(X[bal],X[jobb],Geom.Tav(X[bal],X[jobb])); if (jobb-bal == 2){ // 3 pont van, minden párra kiszámoljuk a táv-ot double t1 = Geom.Tav(X[bal], X[bal+1]); double t2 = Geom.Tav(X[bal+1], X[jobb]); double t3 = Geom.Tav(X[bal], X[jobb]); if (t1 <= t2 && t1 <= t3) return new PontPar(X[bal], X[bal+1], t1); if (t2 <= t3) return new PontPar(X[bal+1], X[jobb], t2); else return new PontPar(X[bal], X[jobb], t3); int kozep=(bal+jobb) >>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<Z[j].y Z[i].y==Z[j].y && Z[i].az<Z[j].az) Y[k++]=Z[i++]; else Y[k++]=Z[j++]; while (i<=kozep) Y[k++]=Z[i++];//a maradékok átmásolása while (j<=jobb) Y[k++]=Z[j++]; k=bal; 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<k && Z[j].y-Z[i].y<kozel.abtav; j++){ double ujtav = Geom.Tav(Z[i], Z[j]); if (ujtav < kozel.abtav){ // kozelebbi párt találtunk kozel.a=z[i]; kozel.b=z[j]; kozel.abtav=ujtav; return kozel; public static PontPar ParKeres(Pont[] P){ int n=p.length; int [] Az=new int[n]; //eredeti pont-azonosítok mentésére Pont[] X=new Pont[n]; //x-szerint rendezett ponthalmaz Pont[] Y=new Pont[n]; //y-szerint rendezett ponthalmaz Pont[] Z=new Pont[n]; //segéd for (int i=0; i<n; i++) X[i]=P[i]; XKoord Xrend=new XKoord();//x-szerinti rendezés relációja Rendez.KupacRend2(X,Xrend);//előrendezés x-koord szerint for (int i=0; i<n; i++){ Az[i]=X[i].az; X[i].az=i; Y[i]=X[i]; //eredeti pont-azonosítók mentése YKoord Yrend=new YKoord();//y-szerinti rendezés relációja Rendez.KupacRend2(Y,Yrend); PontPar Pkozel=ParKeres(X, Y, Z, 0, n-1); //az eredei pont-azonosítók helyreállítása for (int i=0; i<n; i++) X[i].az=Az[i]; return Pkozel; 29