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

E*TRADE. It's your money.
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 la diverse
Date: Mon, 19 Mar 2001 19:01:32 +0200

Hello, folks! Uite si un mesaj ceva mai [foarte] [enorm de] mare in 
care
explic ce am facut eu la problemele propuse de mine si imi dau cu 
parerea
despre subiectele de pe lista. Stiu ca e cam overdue, dar am avut
judeteana... Da, bineinteles c-am luat max...

==========================
=== Belman-Ford pe reale

Ideea e ca trebuie scris
    if(a[j] > a[i] + d[i][j] + EPS)
in loc de
    if(a[j] > a[i] + d[i][j])

Deoarece nu s-a ingramadit nimeni sa explice de ce, iata si explicatia. 
Pe
masinile IEEE, float e reprezentat pe 32 de biti, iar double pe 64. 
Totusi,
x86 are registrii coprocesorului pe 80 de biti (asa-numitul long 
double).
Problema vine de la precizia in plus. De obicei compilatoarele au si 
optiuni
pentru a elimina precizia extra, dar asta incetineste groaznic codul. 
Pentru
a arata care e problema (didactic), sa presupunem ca am lucra in baza 
10 in
loc de 2 si am avea o mantisa de maxim 4 cifre in registri si 3 cifre 
in
memorie (gen long double vs. double). Sa zicem ca avem valorile:
    a[j] = 1.000e0
    a[i] = 0.999e0
    d[i][j] = 0.900e-3 (adica 0.0009)

Coprocesorul calculeaza:
    a[i] + d[i][j] = 0.9999e0 (mantisa de 4 cifre)
    a[j] > a[i] + d[i][j] = 1 (adica adevarat)

Deci se marcheaza schimbarea si in a[j] se scrie (a[i] + d[i][j]), 
adica
0.9999e0. Problema e ca a[j] traieste in memorie, unde mantisa e maxim 
3
cifre, deci 0.9999e0 va fi aproximat evident la 1.000e0. Deci in 
realitate
nimic nu se schimba in memorie, dar programul crede ca a imbunatatit 
ceva.
La pasul urmator va sesiza aceeasi pseudo-imbunatatire, samd.

Despre 1.0/0.0, teoretic pe IEEE-uri ar trebui sa fie +INF. Totusi, nu 
e
recomandabila la concurs, deoarece pe Borland C e +NAN, iar unele 
versiuni
de GCC se simt obligate sa iti de un warning (n-am vazut inca la fata o
asemenea versiune, dar tot imi respingeau sursele la USACO din cauza 
asta,
desi nici una din variantele mele de gcc nu faceau asta).


==========================
=== Broscuta care sare ca virgula calul

Da, eu ma gandeam la flux de cost minim. Mie mi-a luat sub 10 minute sa 
ma
prind de idee si vreo 20 ca sa implementez (what can I say, am muncit 
pentru
aurul ala la inter). Rationamentul a fost cam asa:
1. ce ne cere??? un ciclu elementar intre doua noduri de lungime 
minima?
2. pacat ca zice lungime minima, daca nu era un flux clasic...
3. hopa...

Acum legat de implementare. Exista anumiti programatori care ar 
implementa
asta asa:
1. construieste graf din tabla
2. dubleaza nodurile (pentru capacitati in noduri)
3. fa flux de cost minim

Acesti programatori isi zic algoritmicieni, dar eu prefer denumirea de
tarani. Flux se face foarte bine pe o tabla, fara sa construiesti 
graful; am
facut asta in cateva randuri si timpul de implementare e destul de mic,
oricum nu mai mare decat la un flux pe un graf; doar ca trebuie sa 
gandesti
ce scrii, nu sa torni un algoritm invatat. La fel daca ai un graf cu
capacitati in noduri, se poate face la fel de usor fara sa dublezi 
nodurile
(chiar am facut asta la ONI anu trecut fara nici o dificultate).
Implementati cu grija, algoritmii merg mult mai repede asa. La problema
asta, cred ca e algoritmul are O(N**3), dar probabil mult mai aproape 
de
N**2 (atentie, eu socotesc cu tabla de N**2 casute). Ideea e ca nu iti
trebuie flux maxim, ci flux de cel mult 2. Asta iti simplifica mult si
algoritmul (si scade timpul de implementare).

Cu tot riscul de a-l dezamagi pe Cristian, Mihai are dreptate si 
algoritmul
tau nu merge. Nu prea cred ca merge altceva inafar de flux (sau un 
fluxulet
deghizat, ceva).


==========================
=== Move to front in O(lgN)

Ideea cu arbori echilibrati e buna teoretic, dar nu prea straluceste in
practica. Ideea e ca ai constante (foarte) mari, plus ca daca nu ma 
insel eu
prea tare o operatie iti vine O(lgN), unde N este numarul de caracter
posibile (eg 256). Eu am cerut O(lgK), unde K e pozitia pe care vei 
gasi
caracterul. Asta e mult mai bine in practica, fiindca K-ul e mic de 
obicei
(asta e toate ideea la move-to-front, right?).

Problema se face cu skip-lists. Am citit articolul pe Internet si e 
chiar
grozav. Multumesc pentru sugestie lui Cristian! Daca va intrebati, 
problema
NU apare in articolul ala (ce naiba, doar nu copiez probleme pur si
simplu...). Oricum cine nu a citit articolul, chiar ii recomand sa-l
citeasca. Am facut si teste practice si skip-lists merg excelent. 
Adresa
era: ftp://ftp.cs.umd.edu/pub/skipLists/skiplists.pdf

BTW, daca va uitati pe pagina autorului, gasiti o lucrare in care 
explica ca
formatul binarelor Java e groaznic si el a inventat o metoda care 
scoate
compresii de vreo 1:20. Plus o studiu bine argumentat numit "The Java 
Memory
Model is Hopelessly Flawed". Asta pentru fanii Java.


==========================
=== Chaos from order

Well, well... Dupa cum e formulata problema, presupun ca vrei sa afli 
daca
membrii listei stiu sa faca un merge sau un qsort calumea 
(median-of-three,
optimizarile alea pentru stiva O(lgN) etc.). Eu personal raman la 
preferinta
mea pentru heapsort la concurs, dar pe 1M merge probabil groaznic, 
deoarece
nenoroceste cache-ul procesorului (pe de alta parte quick si merge sunt
foarte localizate). Despre regula cu max 40 de linii, poate tu nu ai 
vazut
flux maxim scris in <700 de caractere (daca TOP e abonat cumva la 
lista:
ti-am batut recordul de la lot din '98).

Programul meu merge in 7 sec (generarea fisierului de intrare in 4sec), 
ceea
ce e foarte bine avand in vedere ca e sub Borland C si n-ai memorie. 
Ideea e
sa faci qsort pe bucati mari si sa interclasezi dup-aia bucatile cu
heap-uri. Programul are peste 10k, dar e si portabil (merge atat sub 
DOS,
cat si pe sisteme POSIX).

Totusi, ideea lui Mihai e super (adica ce ne-a interzis sa facem). Daca
sortezi intai dupa mantise (cu radix) si apoi dupa exponenti (tot cu 
radix),
chiar merge pe IEEE-uri (e un fel de generalizare la radix). Daca ai si
numere negative si pozitive, trebuie sa le sortezi separat.

Promit ce implementez quick, merge, heap si radix pe 1M de double-uri 
maine
sau poimaine si va trimit rezultatele. Presupui ca nu vrei bucket sau 
alte
minuni d'astea probabiliste (daca pui limita de 5*solutia comisiei, 
presupun
ca nu vrei chestii probabilistice).

Inca o nota: daca foloseste cineva qsort-ul din C si se incadreaza in 
de 5
ori solutia comisiei inseamna ca comisia a dat ca solutie bubble-sort. 
Ideea
e ca qsort() face un apel la fiecare comparatie, iar un apel costa 
enorm.
BTW, sub Linux qsort() e implementat cu merge-sort :-)

Si-nca o nota la propunerea de rezolvare cu template-uri C++. La 
concurs nu
e recomandabil sa folosesti asta (adica nu prea merg template-urile pe
compilatoarele date; la USACO zice clar "do not use..."). Plus, credeam 
ce e
o lista pentru algoritmicieni, nu persoane care programeaza tragand
compenente cu mouse-ul in fereastra :-)... Daca vrei, punem pariu ca 
iti
implementez ceva care sa mearga de 5 ori mai repede ca template-urile.

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.