Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: permutacje? kombinacje? php c++ excel - help needed ..
Forum PHP.pl > Forum > Przedszkole
pwsmile
Witam i proszę o pomoc ..

nie mogę rozgryźć następującej sprawy..

mam dane :

- x liczb (np.5 liczb i np. takie : 1 2 3 4 5 , ale może być też: 1 3 3 5 5)

- sumę którą chcę otrzymać z dodania którychś (obojętnie ilu) z danych liczb (np. suma=11)

.. i potrzebuję program / skrypt / arkusz excel, który powie mi jak Abel krowie, które liczby ze zbioru muszą być dodane, żeby utworzyły sumę jaką chcę.

Dla zbioru: 1 2 3 4 5 i danej żądanej sumy 11 byłyby to następujące możliwości:

1_2_3___5 (suma: 11)
__2___4_5 (suma: 11)

Dla zbioru: 1 3 3 5 5 i danej żądanej sumy 11 są 3 możliwości:

__3_3_5__ (suma: 11)
__3_3___5 (suma: 11)
1_____5_5 (suma: 11)

Nie jest ważne ile z liczb podanych w zbiorze złoży się na podaną sumę, jednak każda kolejna z liczb w zbiorze powtarzać się może tylko 1 raz (np. pierwsza liczba w ostatnim przykładzie (1) może byż brana pod uwagę tylko raz, czyli rozwiązaniem nie może być

1_1_1_1_1_1_1_1_1_1_1 (bo liczba 1 w zbiorze wystepuje tylko raz)

ale

liczba 5 - też w drugim przykładzie - powtórzyć się może 2 razy, bo tyle razy wystepuje w zbiorze


Super optymalnie byłoby, gdyby programik w przypadku nie znalezienia pasujących składników dających szukaną sumę, podał najbliższą możliwą kombinację w górę i najbliższą możliwą w dół ..

.. np jezeli żądaną sumą byłaby liczba 2, to mając dany zbiór jak w przykładzie drugim: 1 3 3 5 5 program nie znajdzie wprawdzie odpowiednika, bo suma żadnych ze składników w tym zbiorze nie daje liczby 2, ale wypisze:

1________ (suma: 1, reszta 1)
__3______ (suma: 3, reszta -1)
____3____ (suma: 3, reszta -1)

podobnie dla szykanej sumy 12 i tego samego zbioru: 1 3 3 5 5 pasujący odpowiednik nie zostanie znaleziony, jednak najbliższymi dodatnimi i ujemnymi wartościami będą:

1_____5_5 (suma: 11, reszta 1)
1_3___5_5 (suma: 13, reszta -1)
1___3_5_5 (suma: 13, reszta -1)




Jeżeli ktoś ma jakiś pomysł, lub może już nad czymś takim myslał i ma gotowca, byłbym wdzięczny za udostępnienie.

Pozdrawiam
pwsmile
piotrekkr
z tym problemem to chyba raczej na matematyka.org permutacje komninacje itp mi tez to sie na studiach zaczelo :/
jarrod
  1. <?php
  2. function test($suma=null)
  3. {
  4. if(!$suma) $suma = rand(0,45); // 45 ponieważ 9+9+9+9+9 = 45
  5. if($suma == 0) return 'Zbiór nie zawiera liczb ujemnych. Nie można wykonać działania.';
  6. elseif($suma == 1) return 'Suma == 1 zatem nie można wykonać działań.';
  7.  
  8. $liczby[0] = rand(0,9);
  9. $liczby[1] = rand(0,9);
  10. $liczby[2] = rand(0,9);
  11. $liczby[3] = rand(0,9);
  12. $liczby[4] = rand(0,9);
  13. // posiadamy już pięć losowych liczb które mogą się powtarzać
  14.  
  15. // dla porządku można je posortować
  16. sort($liczby);
  17.  
  18.  
  19. // sprawdzam czy suma wszystkich liczb jest większa od szukanej sumy
  20. // inaczej szykanie nie mam sensu
  21. if(array_sum($liczby) >= $suma) 
  22. {
  23. $breakAll = false; // kontrola wyników
  24. $nSuma = 0; // suma kontrolna
  25. $wynik = array(); // wynik działania funkcji
  26. $tmpKeys = array(); // tu przechowuję indexy liczb użytych w działaniu 
  27.  
  28. // zaczynamy iterowanie po tablicy
  29. for($i=0; $i<5;$i++)
  30. {
  31.  
  32. for($e=$i;$e<5;$e++)
  33. {
  34.  
  35. $tmpKeys[] = $e;
  36. $nSuma += $liczby[$e];
  37.  
  38. if($nSuma == $suma) // znaleziono pasujący wynik
  39. {
  40. $wyn = '';
  41. foreach($tmpKeys as $key)
  42. {
  43. $wyn .= $liczby[$key].'+';
  44. }
  45.  
  46. $wyn = substr($wyn,0,strlen($wyn)-1);
  47. $wyn .= '='.$nSuma;
  48.  
  49. $wynik['dokladnie'][] = $wyn;
  50.  
  51. $nSuma = 0;
  52. $tmpKeys = array();
  53. break;
  54. }
  55. elseif($nSuma > $suma) // znaleziono pierwszy wyższy wynik
  56. {
  57. $wyn = '';
  58. foreach($tmpKeys as $key)
  59. {
  60. $wyn .= $liczby[$key].'+';
  61. }
  62. $wyn = substr($wyn,0,strlen($wyn)-1);
  63. $wyn .= '='.$nSuma;
  64. $resta = $suma-$nSuma;
  65.  
  66. $wynik['wieksze'][] = array($wyn,$resta);
  67.  
  68. $nSuma = 0;
  69. $tmpKeys = array();
  70. break;
  71. }
  72. elseif($e == 4) // ostatni element -> suma wszystkich pozostałych jest mniejsza od szukanej sumy
  73. {
  74. $breakAll = true;
  75.  
  76. $wyn = '';
  77. foreach($tmpKeys as $key)
  78. {
  79. $wyn .= $liczby[$key].'+';
  80. }
  81. $wyn = substr($wyn,0,strlen($wyn)-1);
  82. $wyn .= '='.$nSuma;
  83. $resta = $suma-$nSuma;
  84.  
  85. $wynik['mniejsze'][] = array($wyn,$resta);
  86.  
  87. $nSuma = 0;
  88. $tmpKeys = array();
  89. break;
  90. }
  91. }
  92.  
  93. if($breakAll) break;
  94.  
  95. }
  96. }
  97. else
  98. {
  99. $wynik['max'] = array_sum($liczby);
  100. }
  101. $wynik['liczby'] = $liczby;
  102. $wynik['suma'] = $suma;
  103. return $wynik;
  104. }
  105.  
  106. $wyniki = test();
  107.  
  108. $ret = 'Wynik działania programu:<br/>';
  109.  
  110. if(is_array($wyniki))
  111. {
  112. $ret .= '<br/>Liczby w zbiorze: '.implode(',',$wyniki['liczby']);
  113. $ret .= '<br/>szukana suma: '.$wyniki['suma'].'<br/>';
  114.  
  115. if(isset($wyniki['dokladnie']))
  116. {
  117. $ret .= '<br/>Dokładny wynik daje suma liczb:<br/>';
  118.  
  119. foreach($wyniki['dokladnie'] as $wyn)
  120. $ret .= $wyn.'<br/>';
  121. }
  122. if(isset($wyniki['wieksze']))
  123. {
  124. $ret .= '<br/>Sumę minimalnie większą dają liczby:<br/>';
  125.  
  126. foreach($wyniki['wieksze'] as $wyn)
  127. $ret .= $wyn[0].' reszty: '.$wyn[1].'<br/>';
  128. }
  129. if(isset($wyniki['mniejsze']))
  130. {
  131. $ret .= '<br/>Sumę minimalnie mniejszą dają liczby:<br/>';
  132.  
  133. foreach($wyniki['mniejsze'] as $wyn)
  134. $ret .= $wyn[0].' pozostaje: '.$wyn[1].'<br/>';
  135. }
  136.  
  137. if(isset($wyniki['max']))
  138. {
  139. $ret .= 'Suma wszyskich liczb zbioru ('.$wyniki['max'].') jest mniejsza od podanej sumy.';
  140. }
  141. }
  142. else
  143. {
  144. $ret .= $wyniki;
  145. }
  146. echo $ret;
  147. ?>


uff aarambo.gif
pwsmile
Dzięki piotrekkr, byłem na matematyka.org i nie do końca znalazłem jak to ugryźć.

.

Dla jarrod extra wieeeeelkie DANKE !

Przetestowałem skrypt i to jest exactly to o czym talking about exclamation.gif

Masz u mnie flaszkę .. winksmiley.jpg

Coś tylko jest w obliczeniach chyba jeszcze nie tak, bo wyniki się czasem nie zgadzają.

Wpisz prosze do bazy liczby 1 5 6 7 7 i daj szukanie sumy 21

Własnie mam to w wyniku kodu i wygląda to tak:


Wynik działania programu:

Liczby w zbiorze: 1,5,6,7,7
szukana suma: 21

Sumę minimalnie większą dają liczby:
1+5+6+7+7=26 reszty: -5
5+6+7+7=25 reszty: -4

Sumę minimalnie mniejszą dają liczby:
6+7+7=20 pozostaje: 1


.. czyli gdzieś się program machnął, bo 1+6+7+7 daje 21 bez reszty, a wynik nie podaje tej informacji

Podobnie (może przyczyna jest ta sama i jest to poprostu już konsekwencją owego błędu) podawane propozycje liczb minimalnie większych i mniejszych nie zawsze są zgodne z prawdą


Poza tym przerobiłem Twój kod podając moje konretne przykłady, w których pojawiają się ułamki z dwoma miejscami po przecinku (kropce), jak i podałem własną, faktycznie szukaną sumę. Załączam kod, ponieważ nie wiem czy zmieniając coś w tablicy, nie zmieniłem czegoś, czego nie powinienem.

  1. <?php
  2. function test($suma=null)
  3. {
  4. if(!$suma) $suma = (251.16); // podana suma jest rzeczywistym szykanym wynikiem
  5. if($suma == 0) return 'Zbiór nie zawiera liczb ujemnych. Nie można wykonać działania.';
  6. elseif($suma == 1) return 'Suma == 1 zatem nie można wykonać działań.';
  7.  
  8. $liczby[0] = (64.77);
  9. $liczby[1] = (52.59);
  10. $liczby[2] = (54.18);
  11. $liczby[3] = (42.55);
  12. $liczby[4] = (50.18);
  13. $liczby[5] = (52.59);
  14. $liczby[6] = (50.35);
  15. $liczby[7] = (51.88);
  16. $liczby[8] = (53.12);
  17. $liczby[9] = (49.15);
  18. $liczby[10] = (47.05);
  19. $liczby[11] = (52.83);
  20. $liczby[12] = (53.55);
  21. $liczby[13] = (52.96);
  22. $liczby[14] = (51.98);
  23.  
  24.  
  25.  
  26. //
  27. // wpisałem własne liczby jako konkretny przykład
  28. //
  29.  
  30.  
  31.  
  32. // dla porządku można je posortować
  33. sort($liczby);
  34.  
  35.  
  36. // sprawdzam czy suma wszystkich liczb jest większa od szukanej sumy
  37. // inaczej szykanie nie mam sensu
  38. if(array_sum($liczby) >= $suma) 
  39. {
  40. $breakAll = false; // kontrola wyników
  41. $nSuma = 0; // suma kontrolna
  42. $wynik = array(); // wynik działania funkcji
  43. $tmpKeys = array(); // tu przechowuję indexy liczb użytych w działaniu 
  44.  
  45.  
  46.  
  47.  
  48. // wartość końcową dla tablicy i pętli poniżej zmieniłem na <15 ale niestety nie jestem pewien czy to tak ma być
  49.  
  50.  
  51.  
  52.  
  53. // zaczynamy iterowanie po tablicy
  54. for($i=0; $i<15;$i++)
  55. {
  56.  
  57. for($e=$i;$e<15;$e++)
  58. {
  59.  
  60. $tmpKeys[] = $e;
  61. $nSuma += $liczby[$e];
  62.  
  63. if($nSuma == $suma) // znaleziono pasujący wynik
  64. {
  65. $wyn = '';
  66. foreach($tmpKeys as $key)
  67. {
  68. $wyn .= $liczby[$key].'+';
  69. }
  70.  
  71. $wyn = substr($wyn,0,strlen($wyn)-1);
  72. $wyn .= '='.$nSuma;
  73.  
  74. $wynik['dokladnie'][] = $wyn;
  75.  
  76. $nSuma = 0;
  77. $tmpKeys = array();
  78. break;
  79. }
  80. elseif($nSuma > $suma) // znaleziono pierwszy wyższy wynik
  81. {
  82. $wyn = '';
  83. foreach($tmpKeys as $key)
  84. {
  85. $wyn .= $liczby[$key].'+';
  86. }
  87. $wyn = substr($wyn,0,strlen($wyn)-1);
  88. $wyn .= '='.$nSuma;
  89. $resta = $suma-$nSuma;
  90.  
  91. $wynik['wieksze'][] = array($wyn,$resta);
  92.  
  93. $nSuma = 0;
  94. $tmpKeys = array();
  95. break;
  96. }
  97.  
  98.  
  99.  
  100.  
  101. // Poniżej zmieniłem 4 na 14, bo taki nr ma teraz ostatnia liczba, ale bardziej na
     intuicję niż wiedzę
  102.  
  103.  
  104.  
  105.  
  106. elseif($e == 14) // ostatni element -> suma wszystkich pozostałych jest mniejsza od szukanej sumy
  107. {
  108. $breakAll = true;
  109.  
  110. $wyn = '';
  111. foreach($tmpKeys as $key)
  112. {
  113. $wyn .= $liczby[$key].'+';
  114. }
  115. $wyn = substr($wyn,0,strlen($wyn)-1);
  116. $wyn .= '='.$nSuma;
  117. $resta = $suma-$nSuma;
  118.  
  119. $wynik['mniejsze'][] = array($wyn,$resta);
  120.  
  121. $nSuma = 0;
  122. $tmpKeys = array();
  123. break;
  124. }
  125. }
  126.  
  127. if($breakAll) break;
  128.  
  129. }
  130. }
  131. else
  132. {
  133. $wynik['max'] = array_sum($liczby);
  134. }
  135. $wynik['liczby'] = $liczby;
  136. $wynik['suma'] = $suma;
  137. return $wynik;
  138. }
  139.  
  140. $wyniki = test();
  141.  
  142. $ret = 'Wynik działania programu:<br/>';
  143.  
  144. if(is_array($wyniki))
  145. {
  146. $ret .= '<br/>Liczby w zbiorze: '.implode(',',$wyniki['liczby']);
  147. $ret .= '<br/>szukana suma: '.$wyniki['suma'].'<br/>';
  148.  
  149. if(isset($wyniki['dokladnie']))
  150. {
  151. $ret .= '<br/>Dokładny wynik daje suma liczb:<br/>';
  152.  
  153. foreach($wyniki['dokladnie'] as $wyn)
  154. $ret .= $wyn.'<br/>';
  155. }
  156. if(isset($wyniki['wieksze']))
  157. {
  158. $ret .= '<br/>Sumę minimalnie większą dają liczby:<br/>';
  159.  
  160. foreach($wyniki['wieksze'] as $wyn)
  161. $ret .= $wyn[0].' reszty: '.$wyn[1].'<br/>';
  162. }
  163. if(isset($wyniki['mniejsze']))
  164. {
  165. $ret .= '<br/>Sumę minimalnie mniejszą dają liczby:<br/>';
  166.  
  167. foreach($wyniki['mniejsze'] as $wyn)
  168. $ret .= $wyn[0].' pozostaje: '.$wyn[1].'<br/>';
  169. }
  170.  
  171. if(isset($wyniki['max']))
  172. {
  173. $ret .= 'Suma wszyskich liczb zbioru ('.$wyniki['max'].') jest mniejsza od podanej sumy.';
  174. }
  175. }
  176. else
  177. {
  178. $ret .= $wyniki;
  179. }
  180. echo $ret;
  181. ?>



Jeszcze raz bardzo dziękuję za pomoc.

Jeżeli temat błędu w kodzie nie jest zawiły do poprawki i nie zniechęciłem Cię jeszcze, byłbym bardzo wdzięczny za korektę. Z importem albo ręcznym zaktualizowaniem danych w kodzie będę sobie już potem jakoś za każdym razem radził.

Pozdrawiam serdecznie
pwsmile :roll2:
jarrod
Dałem Ci ramy do stworzenia tego czego chcesz.
Brakuje tam warunków aby program działał pewniej. Widzisz, o godzinie 2 w nocy, mając na 9 rano do pracy, jakoś nie chciało mi się już dłużej nad tym siedzieć winksmiley.jpg

Jesśli chodzi o warunki pętli to są prawidłowe. Szukasz do elemenu mniejszego od sumy elementów w tablicy (w tym przypadku można użyć również $i<= 14 co daje to samo). Inaczej pętla obiegnie tablice za mało razy i funkcja nie zadziała prawidłowo bo nie będzie iterować po wszystkich elementach a jak za dużo to niepotrzebnie wydłuzy się czas działania.

Poprawki wyglądają na prawidłowe.

Jeśli chcesz aby to pewniej działało to najlepiej narysuj sonie winksmiley.jpg jak ta funkcja działa i wówczas będziesz widział jakie warunki należy dodać aby pokazywało dokładne wyniki.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.