losowanie bez powtórzeń

0

Hej mam problem jak zrobić aby wylosować 20 liczb bez powtórzeń próbowałem już chyba na wszystkie sposoby ale nie wychodzi a jest mi to bardzo potrzebne do szkoły jeżei ktoś by mi pomógł byłbym bardzo wdzięczny z góry dziękuje

0

help -> randomize;

0

Metoda losowania bez powtórzeń zależy od wielu czynników. Jest ich wiele, więc postaram się przedstawić najpopularniejsze z nich:

  • metoda przez mieszanie [elementy małe (np.: liczby), zakres elementów zbioru znany przed losowaniem]

Na początku tworzysz zbiór wszystkich możliwych elementów, na przykład w tablicy. Jeśli chcesz, by losowane były liczby od 1 do 100 bierzesz tablicę 100 elementową i wypełniasz ją po kolei liczbami od 1 do 100. Następnie przechodzisz do fazy losowania: losujesz dwie liczby z zakresu takiego, jakie są indeksy tablicy - nazwijmy je 'i' oraz 'j'. Zamieniasz ze sobą miejscami element[i] oraz element[j]. Losowanie powtarzasz do momentu, aż uznasz, że przemieszanie jest wystarczające (np.: 1000 razy) - ważne jest to, że ilość elementów i pętli przemieszania radykalnie wpływa na szybkość. Ostatecznie możesz odczytywać elementy z tablicy po kolei, gdyż pod kolejnymi indeksami znajdują się już przemieszane wartości. Ważne jest to, że - jeśli użyjesz wszystkich liczb losowanych (bez powtórzeń) - to przed kolejnymi odczytami tablicę znów musisz przemieszać. Korzystnym na ogół jest fakt, że całe przemieszanie może być dokonane przed kodem, gdzie już potrzebne będą liczby losowe bez powtórzeń. Inną zaletą jest to, że możesz zbiór liczb losowanych określać dowolnie (np.: określone wartości mogą występować określoną ilość razy) - mieszana będzie tylko kolejność, ale w zbiorze nie pojawią się nowe wartości.

  • metoda przez mieszanie struktur [struktury lub duże obszary pamięci, zakres elementów znany przed losowaniem] - to jest pewna modyfikacja.

Jedyną różnicą jest to, że nie zamieniasz miejscami trzymanych w tablicy struktur, bo może to być czasochłonne, nie mówiąc o zasobach systemu. W tablicy trzymasz jedynie indeksy elementów z tablicy w której są trzymane, albo bezpośrednio - adresy struktur. Reszta mieszania wygląda identycznie.

  • metoda przez sprawdzanie [początkowo nie zawsze znany pełen zbiór mozliwych wartości, elementy dowolne]

Metoda ta nie wymaga uprzedniej generacji liczb - są one wyznaczane przy losowaniu każdej z nich. Wadą tego rozwiązania jest zajmowanie pamięci przez tzw. historię losowań, gdyż metoda ta polega na losowaniu wartości (jakiejkolwiek ze zbioru) i sprawdzaniu, czy wcześniej wystąpiła, jeśli tak, wartość losowana jest ponownie. Zaletą jest możliwość poszerzania zakresu pomiędzy kolejnymi losowaniami (gdyż nowe wartości po prostu nie były jeszcze nigdy użyte). Wady są dosyć duże: kolejne losowania trwają coraz dłużej, gdyż coraz częściej początkowo losowane sa elementy, które już wystąpiły, i trzeba losować ponownie (do skutku). Należy też dbać, aby nie dojść do zapętlenia losowań, gdy nie ma już wolnych elementów. Można temu zapobiec licząc ile w zbiorze pozostało elementów do wylosowania.

  • metoda przez sprawdzanie struktur [trudna czasem do implementacji]

Jest to modyfikacja poprzedniej, z tym, że nie zapisujemy historii losowanych struktur, a jedynie opis ich cech, w najprostszym przypadku sumę kontrolną lub 'hash-code', w każdym razie jakiś możliwie unikatowy opis, który będzie zajmował znacznie mniej niż struktura. Dopiero ten opis zapisujemy w tabeli. Problem polega na tym, że należy tak dobrać opis cech, aby różne kombinacje miały różne opisy. W innym przypadku nie jest gwarantowane pełne wykorzystanie zbioru albo unikatowość losowań.

  • metoda przez eliminację [dobra dla małych zbiorów]

Należy wygenerować tablicę i wpisać do niej wszystkie możliwe wartości ze zbioru. Generowanie polega na wybraniu losowego elementu z całego zbioru, a następnie usunięciu go ze zbioru (na przykład przesunięcie dalszych elementów o jedno miejsce do przodu lub - lepiej - zamiana z ostatnim elementem zbioru). Na końcu traktujemy zbiór jako mniejszy o jeden element i z niego losujemy na tej samej zasadzie kolejną liczbę. Jeśli zbiór po usunięciu elementu (lub przesunięciu na koniec i zmiejszeniu zbioru) został pusty, skończyły się liczby niepowtarzalne. Kolejna seria może się rozpocząć od przywrócenia licznikowi długości tablicy wartości początkowej, oczywiście tylko gdy elementy przesuwano na koniec. Zaletą usuwania elementów całkiem z tablicy jest, mimo wolniejszego działania przy przesuwaniu całej tablicy, stopnoiwe zwalnianie pamięci po wylosowanych już elementach.

-- Są jeszcze inne, matematyczne i algorytmiczne metody generacji liczb losowych bez powtórzeń, ale w tym przypadku odsyłam do literatury z tej dziedziny.

Powodzenia ;)

0

Czy nie wystarczy wylosowane liczby zapisywać kolejno do tablicy, i <ort>karzde </ort>nowe lopsowanie powtarzać, jeśli wylosowana liczba jest już w tablicy?

Oczywiście korzystamy z randomize

0

Jako masz wylosować 20 liczb, to polecam metodę przez mieszanie (pierwsza powyżej). Stwórz tablicę 20 elementów po kolei:

tab: array[1..20] of byte;

{ ... }
var i:byte;
begin
for i:=1 to 20 do
tab[i]:=i;
{ ... }
end

następnie pomieszaj elementy zamieniając ze sobą pary liczby (indeksy zamienianych liczb wylosuj np.: funkcją random( .. ); ). Takie mieszanie zrób minimuj 1000 razy. W tablicy powinne być już pomieszane liczby od 1 do 20. Możesz wypisać lub użyć je po kolei. Koniec. Kropka. :)

0

jak do szkoly to chyba w pascalu :)

uses CRT;
var L:set of Byte;    Li,i:Byte;
begin
  ClrScr;
  for i:=1 to 20 do
  begin
    repeat
      Li:=random(25);
    until not(Li in L);
    L:=L+[Li];
    WriteLn(i,': ', Li);
  end;
  ReadLn;
end.

Nie sprawdzalem czy dziala :]

// @Szczawik - a gdize bylo powiedziane ze liczby mają być od 1 do 20 ? :>

0

Jeśli już to chyba:

var
  L:set of Byte;
  Li,i:Byte;
begin
  randomize();
  for i:=1 to 20 do
  begin
    repeat
      Li:=random(20)+1;
    until not(Li in L);
    L:=L+[Li];
    WriteLn(i,': ', Li);
  end;
end;

Losujemy przecież liczby od 1 do 20 (czyli random od 0 do 19, a potem +1). Ale zauważcie, jak długo czasem potrafi losować ostatnie liczby.

To jednak działa szybciej:

var
  L: array [1..20] of byte;
  i:Byte;
  a,b,temp:Byte;
begin
  for i:=1 to 20 do
    L[i]:=i;
 randomize();
  for i:=0 to 255 do
  begin
    a:=random(20)+1;
    b:=random(20)+1;
    temp:=L[a];
    L[a]:=L[b];
    L[b]:=temp;
  end;
  for i:=1 to 20 do
    WriteLn(i,': ', L[i]);
end;

Cóż.. warto się pobawić :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1