Losowanie bez powtórzeń i wkładanie do indexu


(Ollo98) #1

Siema, może mi ktoś zmodyfikować ten kod tak, aby było 10 wylosowanych liczb.

Jest tablica z 10 nazwami typu string.

Chcę aby każda wylosowana liczba trafiała do indexu tej tablicy.

Coś na zasadzie 

nazwy[rand()%10]

 nie zrobię bo liczby będą się powtarzać. ;/

#include <iostream>
#include <cstdlib>
#include <ctime>

bool czyBylaWylosowana( int iLiczba, int tab[], int ile )
{
    if( ile <= 0 )
         return false;
    
    int i = 0;
    do
    {
        if( tab[ i ] == iLiczba )
             return true;
        
        i++;
    } while( i < ile );
    
    return false;
}

int wylosuj()
{
    return( rand() % 10 ) + 1;
}

int main()
{
    srand( time( 0 ) );
    int wylosowane[ 5 ];
    int wylosowanych = 0;
    do
    {
        int liczba = wylosuj();
        if( czyBylaWylosowana( liczba, wylosowane, wylosowanych ) == false )
        {
            wylosowane[ wylosowanych ] = liczba;
            wylosowanych++;
        } //if
    } while( wylosowanych < 5 );
    
    wylosowanych = 0;
    do
    {
        std::cout << wylosowane[ wylosowanych ] << std::endl;
        wylosowanych++;
    } while( wylosowanych < 5 );
    
    return 0;
}

(floyd) #2

Czy widziałeś losowanie w lotto i dlaczego nie powtarzają się wylosowane numery?

To proste, wylosowana kula nie trafia już do bębna i wobec tego nie można już jej wylosować. :slight_smile:

Wystarczy zatem zaprogramować to co świetnie rozumiemy w realnej rzeczywistości.

Weźmy obrazowo zbiór tekstowy: {1,2,3,4,5,6,7,8,9,10}

Losujemy za pierwszy razem tak jak napisałeś: nazwy[rand()%10]

Załóżmy że wylosowałeś liczbę 4 i to będzie pierwsza wylosowana liczba. Usuwamy następnie z naszego zbioru liczbę na 4 pozycji, pozostanie nam teraz zbiór:{1,2,3,5,6,7,8,9,10} który zawiera już tylko 9 elementów, zatem następne losowanie musi być z dziewięciu liczb czyli:nazwy[rand()%9]

załóżmy, że wylosowałeś liczbę 7, to następną wylosowaną liczbą nie będzie już liczba 7, ale liczba która znajduje sie w naszym zbiorze na 7pozycji.

Jak łatwo sprawdzić na 7 pozycji jest liczba 8 i to będzie druga z kolei liczba którą uznamy za wylosowaną. Mamy już dwie wylosowane liczby:{4,8}

Ponownie zmniejszamy nasz zbiór o ten wylosowany element czyli otrzymamy zbiór:{1,2,3,5,6,7,9,10}

Ponawiamy losowanie ale już z 8 elementów czyli :nazwy[rand()%8]  itd itd.

Można też to samo zaprogramować na tablicach tworząc np. po każdym wylosowaniu  tablicę bez już wylosowanego elementu wcześniej elementu, czyli tak jak w Lotto.

A, tak przy okazji, to wydaje mi się, że czasami przy programowaniu nawet nie próbujemy się sugerować rozwiązaniami znanymi z realu.

Swego czasu miałem do rysowania prostokąty o zmieniającej się wysokości, ale byl z tym pewien kłopot i nie wyglądało to dobrze. Dopiero spojrzenie na okno w mieszkaniu pozwoliło mi znaleźć idealne rozwiązanie i krzyknąć: Eureka!Jeżeli chcemy aby okno było 'mniejsze' to nie zmniejszamy go, tylko przesłaniamy od góry żaluzją. To samo zaprogramowałem. Wszystkie prostokąty miały te samą wysokość, a od góry przesłaniałem je tłem. Efekt był taki jak by prostokąty zmieniały swoją wysokość, choć to tylko 'żaluzje' przesłaniały je od góry. :).


(Ollo98) #3

Dzięki Floyd  za szybką odpowiedź i super wytłumaczenie. :slight_smile:

Ale chyba zamiast np. [rand()%9] powinno być rand()%9+1 bo jest numerowanie Amerykańskie, czyli jak napiszemy rand()%9 to się wylosują liczby {0,1,2,3....9},

a jak napiszemy rand()%9+1 to będzie {1,2,3....9,10} . :slight_smile: Tak mi się wydaje. :slight_smile:

Mam teraz taki kod.

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <ctime>
using namespace std;


int main()
{
    string liczby[10]={"a","b","c","d","e","f","g","h","i","j"};
    int n;
    bool wystapil[10] = {false};
    srand(time(NULL));
    for (int i = 0; i < 10; i++)
    {
        do
        {
            n = rand() % 10;
            liczby[n];
        } while(wystapil[n] == true);
        wystapil[n] = true;
    }
//    random_shuffle(liczby, liczby + 4);
    for (int i = 0; i < 10; i++)
        cout << liczby[i];
    cout << endl;
    return 0;
}

Chciałbym żeby literki losowały się w różnej kolejności, a po prostu wyświetlają się w takiej samej jak podałem w tablicy.. Czyli "abcdefghij"..

Zmodyfikuje ktoś ten kod tak żeby losowały się w różnej kolejności? Byłbym bardzo wdzięczny. :slight_smile:


(MetaX) #4
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <ctime>
using namespace std;

bool czyBylaWylosowana( int iLiczba, int tab[], int ile )
{
    if( ile <= 0 )
         return false;
    
    int i = 0;
    do
    {
        if( tab[i] == iLiczba )
             return true;
        
        i++;
    } while( i < ile );
    
    return false;
}

int wylosuj()
{
    return rand() % 10;
}


int main()
{
    string liczby[10]={"a","b","c","d","e","f","g","h","i","j"};
    int n;
    srand( time( 0 ) );
    int wylosowane[10];
    int wylosowanych = 0;
    do
    {
        int liczba = wylosuj();
        if( czyBylaWylosowana( liczba, wylosowane, wylosowanych ) == false )
        {
            wylosowane[wylosowanych] = liczba;
            wylosowanych++;
        }
    } while( wylosowanych < 10 );
	
	wylosowanych = 0;
    do
    {
    	n = wylosowane[wylosowanych];
    	cout << liczby[n];
        wylosowanych++;
    } while( wylosowanych < 10 );
    cout << endl;
    getchar();
    return 0;
}

Proszę :slight_smile:


(Ollo98) #5

Dzięki stary, szukałem tego tyle dni. :D 

Temat rozwiązany. :slight_smile: