I can has Makavelis numbers
Posted in: PHP, Programare, By: SaltwaterC, At: May 13th, 2010
S-a găsit Google Reader să mă scoată cu nasul din shell cu următoarea problemă, dată pe undeva pe aici. Practic rezolvarea problemei:
AB + CD + AC + BD = 100
Ca orice “nerd” ce se respectă, am pus mâna pe Eclipse pentru a rezolva problema, nu pe o foaie de hârtie, din moment ce prin natura ei există 104 ( da, 10.000) soluții posibile, dar doar 25 sunt corecte, considerând faptul că A, B, C pot lua valoarea 0. De fapt, am scris soluția ca pe una configurabilă pentru a-i servi și alt input dacă nu am nimerit-o și A, B, C încep de la 1. Oricum, muncă de 5 minute, dar i-am dat un refactor, să moară dușmanii de ciudă, fără număr la bandă.
Din moment ce propria pacoste de motan mi-a servit drept inspirație, codul e scris lolstyle (dar totuși câtuși de cât profesionist). Ca idee, I_can_has_numbers este clasa ce se ocupă de toate chestiile, iar fișierul I_can_has_everything.php este cel apelabil, fie din browser, pentru cei cu o stivă PHP instalată, fie folosind PHP CLI.
Cod: PHP5/OOP
Download: I_can_has_Makavelis_numbers.zip
Pentru cei născuți cu lene de a mai rula cod, acestea sunt soluțiile:
Number of solutions: 25 A = 0; B = 0; C = 8; D = 6; 0 + 86 + 8 + 6 = 100 A = 0; B = 1; C = 7; D = 6; 1 + 76 + 7 + 16 = 100 A = 0; B = 2; C = 6; D = 6; 2 + 66 + 6 + 26 = 100 A = 0; B = 3; C = 5; D = 6; 3 + 56 + 5 + 36 = 100 A = 0; B = 4; C = 4; D = 6; 4 + 46 + 4 + 46 = 100 A = 0; B = 5; C = 3; D = 6; 5 + 36 + 3 + 56 = 100 A = 0; B = 6; C = 2; D = 6; 6 + 26 + 2 + 66 = 100 A = 0; B = 7; C = 1; D = 6; 7 + 16 + 1 + 76 = 100 A = 0; B = 8; C = 0; D = 6; 8 + 6 + 0 + 86 = 100 A = 1; B = 0; C = 6; D = 7; 10 + 67 + 16 + 7 = 100 A = 1; B = 1; C = 5; D = 7; 11 + 57 + 15 + 17 = 100 A = 1; B = 2; C = 4; D = 7; 12 + 47 + 14 + 27 = 100 A = 1; B = 3; C = 3; D = 7; 13 + 37 + 13 + 37 = 100 A = 1; B = 4; C = 2; D = 7; 14 + 27 + 12 + 47 = 100 A = 1; B = 5; C = 1; D = 7; 15 + 17 + 11 + 57 = 100 A = 1; B = 6; C = 0; D = 7; 16 + 7 + 10 + 67 = 100 A = 2; B = 0; C = 4; D = 8; 20 + 48 + 24 + 8 = 100 A = 2; B = 1; C = 3; D = 8; 21 + 38 + 23 + 18 = 100 A = 2; B = 2; C = 2; D = 8; 22 + 28 + 22 + 28 = 100 A = 2; B = 3; C = 1; D = 8; 23 + 18 + 21 + 38 = 100 A = 2; B = 4; C = 0; D = 8; 24 + 8 + 20 + 48 = 100 A = 3; B = 0; C = 2; D = 9; 30 + 29 + 32 + 9 = 100 A = 3; B = 1; C = 1; D = 9; 31 + 19 + 31 + 19 = 100 A = 3; B = 2; C = 0; D = 9; 32 + 9 + 30 + 29 = 100 A = 5; B = 0; C = 0; D = 0; 50 + 0 + 50 + 0 = 100
Update: F (nu o să îi dezvălui numele din moment ce a decis să se semneze doar cu F
) a atras antețina asupra faptului că am făcut brute-force în soluția mea sofisticată, deci vin în întâmpinare cu un algoritm bazat pe modelarea matematică a soluției. Algoritmul rezolvă problema în numărul minim de pași (24), plus adăugarea soluției iregulate (unde trișez, este hardcoded). Numărul de bucle s-a redus la două cu număr minim de pași (4 pentru A, inițial 9 pentru B, după care scade, C și D sunt deduse).
Download: I_can_has_Makavelis_numbers_v0.2.zip
Update: din moment ce primii doi algoritmi sunt de cacao (fără o), primul e pur brute-force iar al doilea nu reprezintă o modelare matematică ce să includă toate soluțiile, revin pe scenă cu ultima soluție (finală) a problemei de mai sus.
Sursa algoritmului propriu zis:
for ($a = 0; $a < = 5; $a++)
{
$double_a = 2 * $a;
$end_b = 8 - $double_a;
$d = $a + 6;
for ($b = 0; $b <= $end_b; $b++)
{
$c = (8 - $double_a) - $b;
if ($d % 10 === 0)
{
$a++;
$d = 0;
}
$this->solutions[] = array
(
'a' => $a,
'b' => $b,
'c' => $c,
'd' => $d,
);
}
}
Download: I_can_has_Makavelis_numbers_v0.3.zip
cam brute-force pentru atata sofisticare
Chiar e bruteforce. Dar nu atât de lent pe cât pare, deși am zis, e O(n^4) + ceva, n-am mai luat în calcul suma, evaluarea logică și punerea pe stivă. La 00:00 nu prea mai aveam dispoziție de a inventa algoritmi mai deștepți, deși provocarea rămâne. Oricum, din lista de soluții, se observă o regulă la valorile lui A:
- nouă 0 iar B + C + D = 14
- șapte 1 iar B + C + D = 13
- cinci 2 iar B + C + D = 12
- trei 3 iar B + C + D = 11
- un 5 iar B + C + D = 0 (aici nu se păstrează șirul)
Aș cam avea material de început. Problema nu rămâne rezolvată, deși am găsit soluțiile.
pai ceva de genul asta mai taie din solutii cred:
2A + 11B + 11C + 20D = 100
2A + 2*10*D + 11(B+C) = 100
2(A+10D) + 11(B+C) = 100
Exceptând soluția iregulată (ultima, ce nu face parte din iterație), o rezolvare O(m*n) mergând pe șiruri:
$end_b = 8; $start_sum = 14; for ($a = 0; $a < = 3; $a++) { $d = $a + 6; for ($b = 0; $b <= $end_b; $b++) { $c = ($start_sum - $b) - $d; $this->solutions[] = array ( 'a' => $a, 'b' => $b, 'c' => $c, 'd' => $d, ); } $end_b = $end_b - 2; $start_sum--; } $this->solutions[] = array ( 'a' => 5, 'b' => 0, 'c' => 0, 'd' => 0, );Precum vezi, nici nu verific soluția. Rezolvă problema în fix 24 iterații + adăugarea soluției iregulate în stivă. Pentru 5, 0, 0, 0 nu am reușit să fac nici un model matematic.
Am găsit și legătura dintre A = 5; B = 0; C = 0; D = 0 cu restul șirului de valori. Mi-a dat ceva bătaie de cap, observasem 3 caracteristici, dar îmi lipsea a 4-a:
- B incrementează de la 0 până la 8 – 2*A
- C decrementează până la 0 de la 8 – 2*A
- D incrementează de la A+6 până la 0
- La D = 0 (D = 9 incrementat conform șirului) ar trebui să fie 10, dar cum vorbim de cifre, A ce ar trebui să fie 4, preia unitatea de la D și devine 5 (aici aparent se rupe iterația iar soluția pare iregulată) iar D rămâne 0.
Am mai găsit și relația B + C = 8 – 2*A, analizând soluțiile exceptând ultima, din moment ce A + B + C + D = 14 iar 20*A + 11*B + 11*C + 2*D = 100 (B + C = 8 – 2*A se obține prin substituție). E valabilă și pentru A = 4, B = 0, C = 0, deci A-ul se poate incrementa doar la adăugarea în soluție dacă D = 0.
Eficiența algoritmului este identică cu cea a celui implementat anterior, dar e pentru toate soluțiile.
PS: am încercat să caut soluția pentru o permutare completă a celor 4 cifre, AB + BC + CD + DA = 100, dar 11*(A + B + C + D) = 100 este clar problemă fără soluție.
deci… pentru un rahat de algoritm ai facut 3 versiuni
Tu ai făcut doar zgomot. Fă unul mai eficient ca al meu dacă te mai dai mare superstar programator sau taci.
[...] (servletul fractal.c disponibil în arhiva de distribuție), fie că am executat problema despre care vorbeam aici, atât implementarea brută cât și cea eficientă, pe un quad-core (C2Q Q9400) și Apache Bench [...]