Inbox for mugurel_ionut@yahoo.com    Yahoo! - My Yahoo!     Options - Sign Out - Help
Mail    Addresses    Calendar    Notepad   

Click Here!
Download Attachments
    Prev | Next | Inbox
From: "Mihai Patrascu" <mihai_p@pcnet.ro>  | Block Address | Add to Address Book
To: "probleme" <probleme@ldc.ro>
Subject: Re: probleme de geometrie
Date: Tue, 10 Apr 2001 13:19:52 +0300

>                          Test geometrie
>                       ~~~~~~~~~~~~~~~~~~

Problemele sunt interesante. De unde le ai? Mai trimite daca mai ai.


>   1. Se dau coordonatele a n puncte din plan (n<=1000). Gasiti o 
dreapta
> care contine cele mai multe din punctele date.
>  Intrare : fisierul g1.in - contine pe prima linie numarul natural n, 
iar
> pe urmatoarele n linii perechi de numere intregi din intervalul
[-1000,1000]
>  Iesire : in fisierul g1.out se va scrie pe o linie numarul maxim de
> puncte coliniare iar pe urmatoarele linii coordonatele acestor 
puncte.

Solutie in O(N*N*lgN). Pentru fiecare punc, translatezi tot sistemul ca 
si
cum punctul ala ar fi originea si sortezi punctele dupa panta cu 
originea.
In vectorul sortat, punctele coliniare apar pe pozitii consecutive cu 
pante
egale. O idee care iti reduce timpul de rulare si te ajuta putin si la
implementare e sa sortezi la inceput punctele dupa cheia primara x si 
cheia
secundara y si pentru fiecare punct sa consideri apoi decat punctele 
din
cadranele I si II fata de el.

Pentru ca ai numere naturale de modul max 1000, sortarea dupa pante se 
face
superb. Fie (x,y) coordonatele punctului dupa translatie. In loc de 
panta
(double) x/y, poti tine perechea de numere (x/gcd(x,y), y/gcd(x,y)) 
(scuzati
romgleza, gcd e greatest common divisor). Aceasta este o pereche de 
doua
short-uri, care le poti pune in structura de date:
    union {
        long u;
        struct {
            short a, b;
        } pair;
    };

Poti adica sorta numere intregi (campul u). Sortarea merge (mult) mai
repede. Justificarea de ce merge asa e putin mai complicata, dar va 
prindeti
voi.


>   2. Gasiti cercul care contine in interior sau pe circumferinta o 
multime
> de puncte date si care are centrul in unul din aceste puncte.
>  Intreare : Fisierul g2.in contine pe o linie numarul de puncte 
<=300, iar
> pe urmatoarele linii coordonatele acestor puncte, perechi de numere
> intregi din intervalul [-200,200] separate prin spatii.
>  Iesire : Fisierul g2.out va contine 3 numere : o pereche de numere 
fiind
> coordonatele centrului, al treilea numar raza cercului cu 2 zecimale
exacte.

De ce nu poti considera fiecare punct si apoi sa gasesti cel mai 
departat
punct de el? O(N**2). Daca centrul nu e intr-unul din puncte, s-a dat o
rezolvare mai demult pe lista.


>   3. Gasiti o linie franta de lungime minima care uneste n puncte
(n<=100),
> pornind de la un punct dat Po. Punctele au coordonate intregi (x,y) 
cu
> 1<=x<=100, 1<=y<=100.
>  Intrare : fisierul g3.in contine punctele ca mai sus, primul punct 
fiind
Po.
>  Iesire : fisierul g3.out contine pe primul rand lungimea minima, cu 
3
> zecimale, iar pe urmatoarele randuri coordonatele punctelor, in 
ordinea in
> care sunt unite, incepand cu Po.

Problema este NP. E vorba de gasirea unui lant hamiltonian intr-un graf
planar. Faptul ca iti da punctul de pornire nu ajuta prea mult. 
Problema s-a
mai dat la o nationala la clasa X acum vreo doi ani.

O abordare simpla e sa faci un greedy oarecare si eventual un back 
omorat
dup-aia (cu conditii de oprire destepte in back). Cu asta s-a luat max 
la
nationala aia.

O idee mai savanta de euristica e sa incerci sa gasesti un lant 
hamiltonian
bitonic. Un astfel de lant porneste din Po, trece prin unele puncte 
pana la
P de x maxim, crescand mereu x-ul punctelor si apoi se intoarce scazand
mereu x-ul trecand toate punctele pe care nu le-a luat de prima data.
Deseori un lant bitonic e suficient de aproape de optim. Poti incerca 
si
dupa y, nu numai dupa x si apoi inlocuind "spre x maxim" cu "spre x 
minim"
(4 euristici in total). Un astfel de lant minim se determina cu o 
dinamica
cu un tablou de N*N in O(N*N), cred ca va prindeti cum.

Pentru problema unui ciclu hamiltonian intr-un graf planar, exista un
algoritm de aproximare destul de bun care scoate un ciclu de cel mult 2 
ori
mai mare ca optimul. Ideea e sa faci un MST (minimum spanning tree - 
arbore
partial minim) si sa-l parcurgi DF. Unind punctele in ordinea primei
atingeri iti da un astfel de ciclu. Va las pe voi sa va dati seama de 
ce e
de cel mult 2 ori mai lung ca optimul (cheia demonstratiei e ca graful 
e
planar). Acest algoritm se poate adapta pentru lant hamiltonian, taind
muchia care revine in Po la sfarsitul ciclului. O optimizare e sa nu
parcurgi DF oricum, ci astfel incat ultimul nod atins sa fie cel mai
departat de Po. Complexitatea per total e O(N*N) timp cu O(N) memorie.


>   4. Se dau n puncte (n<=200) oricare 3 necoliniare. Gasiti un romb 
cu
> varfurile in punctele date, (daca exista).

O rezolvare evidenta e pentru fiecare punct sortezi celelalte puncte 
dupa
distanta la punctul referinta (cheia primara) si dupa panta cu punctul
referinta (cheia secundara). Apoi iei oricare doua puncte aflate la 
aceeasi
distanta (astfel de puncte sunt consecutive in lista) si formezi rombul 
din
astea doua puncte si punctul de referinta. Al patrulea varf il poti 
cauta in
O(lgN) fiindca poti calcula distanta la punctul referinta si panta lui 
e
media aritmetica pentru pantele celor doua puncte alese. Memorie e O(N) 
si
timp e Omega((N**2)*lgN) si O((N**3)*lgN). Mai strans nu stiu, dar 
pentru
200 sigur intra in timp.

Exista si o rezolvare simplu de implementat O((N**2)*lgN) (problema ar 
fi ca
memoria e O(N**2) - pe Linux am putea avea n <= 1000 fara probleme). 
Ideea e
sa unesti oricare doua puncte. Pentru fiecare segment tii mijlocul si 
panta.
Acum trebuie sa determini daca exista doua segmente perpendiculare cu
acelasi mijloc.

Sa presupunem ca coordonatele sunt numere intregi de modul < 1000. 
Centrele
le tii ca numere intregi (tii (2x,2y) in loc de (x,y)). Panta o tii la 
fel
ca la problema 1, cu o singura modificare. Segmente perpendiculare 
inseamna
produsul pantelor egal cu -1. Deoarece oricare trei puncte sunt 
necoliniare,
nu avem doua structuri egale (aceleasi centre si aceleasi pante). Deci
fiecare panta negativa o modificam si tinem (-1/m) in loc de m (sa 
numim
asta panta normalizata). Problema se reformuleaza: "gasiti daca exista 
doua
segmente cu mijloacele si pantele normalizate egale". Asta se face usor 
cu o
sortare si apoi verificam daca doua elemente consecutive sunt egale. 
Pentru
considerente similare cu prob 1, putem sorta numere intregi de 64 de 
biti in
loc de structuri.

Implementarea e scurta si simpla, iar pe Linux merge pentru N=1000 in 
0.7
sec daca stii s-o faci ca lumea.

>   5. Se dau n puncte cu coordonate pozitive. Gasiti un dreptunghi de 
arie
> minima care contine in interior sau pe frontiera cel putin jumatate 
din
> punctele date.
>   Intrare : Fisierul g5.in contine numarul de puncte, numar natural 
<=1000
> si coordonatele punctelor, numere reale cu 3 zecimale.
>   Iesire : Fisierul g5.out contine coordonatele varfurilor stanga jos 
si
> dreapta sus ale dreptunghiului gasit, cu 3 zecimale.

Hmmm, dupa marimea datelor cred ca trebuie un algoritm O~(N**2)... ma 
mai
gandesc. [Pentru cine nu e tare la teorie, O~ se citeste O moale, tilda 
se
scrie deasupra O-ului si e ca si O numai ca eliminam orice factor lgN 
din
paranteza].


>   6. Se dau n puncte in plan (n<=1000) de coordonate intregi mai mici 
in
> modul ca 250, oricare 3 necoliniare. Gasiti un triunghi cu varfurile 
in
> punctele date de perimetru minim.
>   Intrare : fisierul g6.in - ca mai sus
>   Iesire : fisierul g6.out - varfurile.

Si aicea trebuie tot ceva O~(N**2). Cred ca am chiar o chestie O(NlgN).
Presupun ca stiti algoritmul in O(NlgN) pentru cele mai apropiate doua
puncte. Cred ca merge tot o chestie similara. Singura neclaritate e 
reunirea
celor doua partitii. Se demonstreaza usor ca e suficient sa se 
considere o
banda de P/2 in jurul dreptei verticale dupa care s-a partitionat (unde 
P e
minimul dintre perimetrele minime gasite de o parte si de alta). Tot ce 
mai
ramane sa demonstrez e ca incap O(1) puncte intr-un patrat de P/2*P/2 
astfel
incat sa nu poti forma din ele un triunghi cu perimetrul mai mic de P. 
Nu
prea imi dau seama cat e constanta din O(1), dar nu prea conteaza decat 
daca
exista. Intuitiv exista si am si niste idei cum s-ar putea demonstra. 
La
concurs as fi implementat asta fara nici un dubiu, deoarece chiar daca 
ma
insel si nu exista o astfel de constanta, oricum in practica algoritmul 
va
lua destul teste.

mihai_p

     Prev | Next | Inbox
Download Attachments

Yahoo! Messenger - Send instant messages to friends!
Address Book · Alerts · Auctions · Bill Pay · Bookmarks · Briefcase · Broadcast · Calendar · Chat · Classifieds · Clubs · Companion · Domains · Experts ·Games · Greetings · Home Pages · Invites · Mail · Maps · Member Directory · Messenger · My Yahoo! · News · PayDirect · People Search · Personals · Photos · Shopping · Sports · Stock Quotes · TV · Travel · Weather · Yahooligans · Yellow Pages · more...

Privacy Policy- Terms of Service - Guidelines
Copyright © 1994-2001 Yahoo! Inc. All rights reserved.