• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

question-closed Program ma za zadanie wylosować numerek z dziennika wykluczając z losowania numery nieobecnych osób.

0 głosów
782 wizyt
pytanie zadane 4 lutego 2019 w C i C++ przez Trzeci Nowicjusz (220 p.)
zamknięte 10 stycznia 2020 przez Trzeci
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;

int main()
{
    int ile_uczniow,ile_nieobecnych,losowanie,numerek[ile_nieobecnych],x;

    cout << "Podaj ilosc uczniow: ";
    cin>>ile_uczniow;

    cout << "Podaj ilosc nieobecnych uczniow: ";
    cin>>ile_nieobecnych;
    cout <<endl;


    for(int i=0; i<=ile_nieobecnych; i++)

    {
        cout<<"Podaj numerek:";
        cin>>numerek[i];

    }


    cout <<endl;
    x = ile_uczniow - ile_nieobecnych;


    while(losowanie!=numerek)
    {
        srand(time(NULL));
        losowanie = rand()%x+1;
    }


    cout <<"Wylosowany numer to: "<<losowanie;
    cin.get();
    return 0;
}

W czym tkwi błąd???Czy jest inny sposób na wykluczenie liczb z losowania??? błąd występuje w pętli while

komentarz zamknięcia: ...
komentarz 4 lutego 2019 przez mokrowski VIP (148,200 p.)

Tu masz raczej błędy koncepcyjne. Kilka pytań:

1. Co jeśli wprowadzę ilość nieobecnych większą niż uczniów?

2. Jeśli losujesz nieobecnego, następny nieobecny będzie z pozostałych uczniów. Jeśli będziesz losował nieobecnych ze wszystkich uczniów, będziesz miał błąd wylosowania ucznia który już jest nieobecny ("gubisz jednego nieobecnego")

Chyba zgadzasz się że: ilość_nieobecnych + ilość_obecnych == ilość_uczniów ?

 

komentarz 4 lutego 2019 przez Trzeci Nowicjusz (220 p.)
A masz  jakiś pomysł na ten kod???Z góry dziękuje za pomoc ;)
komentarz 4 lutego 2019 przez Mavannkas Bywalec (2,290 p.)
Zaraz go dokleję do mojej odpowiedzi :)

1 odpowiedź

0 głosów
odpowiedź 4 lutego 2019 przez Mavannkas Bywalec (2,290 p.)
wybrane 4 lutego 2019 przez Trzeci
 
Najlepsza

Tablica nie ma wartości zdefiniowanej podczas tworzenia. Podczas tworzenia tablicy jej wielkość jest losowa. (8 linia)

srand nie powinno być w pętli bo się krzaczy ;-) (33 linia)

x nie powinno być granicą losowania, przecież jeśli nie ma 4 osób np 1,2,3,4 to dalej może być osoba z nr 30 co nie? (28 linia)

W warunku kończącym pętle nie masz żadnej zmiennej odpowiadającej za przechodzenie po tablicy "numerek" intiger nie może być porównany do wskaźnika (wszystko wywala kompilator)(31 linia)

Zdefiniuj ją po wczytaniu ilości nieobecnych. A poza tym aby program działał poprawnie polecam wczytanie wszystkich numerów, wylosowanie liczby od 1 do 30 i późniejsze sprawdzanie czy wylosowany numer przypadkiem nie jest w tablicy nieobecnych,

#include <iostream>
#include <ctime>
#include <cstdlib>
int load()
{
    int bufor;
    while(true)
    {
        std::cin>>bufor;
        if(!std::cin.fail())
            break;
        std::cin.clear();
        std::cin.ignore(1000,'\n');
        std::cout<<"Wartosc nie jest liczba\n";
    }
    return bufor;

}
int main ()
{
    srand(time(NULL));
    int maxPupil, absPupil,* T=nullptr, siz=0;
    std::cout<<"Podaj ile uczniow jest w klasie (liczac nieobecnych) ";
    maxPupil=load();
    std::cout<<"Podaj numery nieobecnych uczniow (jak skonczysz wprowadz 0) ";
    while( true )
    {
        absPupil=load();
        if( absPupil == 0 )
             break;
        if(!(absPupil>0&&absPupil<=maxPupil))
        {
            std::cout<<"Zly numer\n";
            continue;
        }
        int * nw = new int[ siz + 1 ];
        for( int i = 0; i < siz; ++i )
             nw[ i ] = T[ i ];
        nw[ siz ] = absPupil;
        delete[] T;
        T = nw;
        siz++;
    }
    int ran;
    bool flage=true;
    while(flage)
    {
        flage=false;
       ran=std::rand()%maxPupil+1;
       for(int i=0;i<siz;i++)
        if(T[i]==ran)
        {
         flage=true;
         break;
        }
    }
    std::cout<<"Szczesliwy numerek to... "<<ran;
}

 

komentarz 4 lutego 2019 przez Trzeci Nowicjusz (220 p.)
Dziękuje za pomoc :)
komentarz 4 lutego 2019 przez Mavannkas Bywalec (2,290 p.)
I jak dajesz radę?
komentarz 4 lutego 2019 przez mokrowski VIP (148,200 p.)

@Mavannkas,

...wylosowanie liczby od 1 do 30 i późniejsze sprawdzanie czy wylosowany numer przypadkiem nie jest w tablicy nieobecnych...

A co jeśli generator liczb losowych będzie "z uporem maniaka" losował w pętli samych już nieobecnych? Jest takie prawdopodobieństwo. Masz program który albo nie skończy się nigdy albo kiedyś się skończy... ogólnie jest niedeterministyczny. Patrz mój komentarz wyżej.

komentarz 4 lutego 2019 przez Mavannkas Bywalec (2,290 p.)
W sumie nawet o tym nie pomyślałem... Jedyne rozwiązanie tego problemu jakie przychodzi mi do głowy na teraz (uwzględniając to że uczę się tego dość krótko) to napisanie wyjątku który np po 100 nieudanych próbach wylosowania liczby wychodzi z losowania i przechodzi do pętli od 1 do x i proponuje najmniejszy poprawny numerek.

Chętnie posłucham co możesz podpowiedzieć :) przynajmniej się czegoś dowiem od kogoś bardziej doświadczonego :D

Edit: Może pomogłoby zmniejszenie zakresu losowanych liczb o podane numery aby wylosowane zawsze były inne ale nie dałbym rady jeszcze tego zaimplementować
komentarz 4 lutego 2019 przez mokrowski VIP (148,200 p.)

Dobrze.. Podam algorytmy bo podawanie rozwiązania było by pozbawianiem celu samego ćwiczenia.

1. Wybierasz losowo jakiegoś ucznia z początkowego zakresu wszystkich uczniów i zamieniasz go z ostatnim. Zakres tak wybierania losowego jak i "indeks na końcu" maleje przy każdym wyborze. Wyborów jest tyle ile zadano jako ilość nieobecnych. Po tych operacjach przyjmujesz że "w ogonie tablicy" są nieobecni a na początku obecni. Z zakresu obecnych losujesz jednego. Zakres obecnych to indeksy [0, ilosc_uczniow - ilosc_nieobecnych - 1]. Te "minus jeden" bo tablice indeksujemy od 0.

2. Całą tablicę tasujesz jak w talii kart. Możesz po prostu przejść po niej tyle razy ilu masz uczniów i dla 2 losowych indeksów z całego zakresu, zamienić uczniów. Po tej operacji przyjmujesz że "w ogonie są nieobecni" (a już wiesz jak policzyć "zakres ogona"), a na początku są obecni.

Algorytm 1 jest wydajny a 2 jest łatwiejszy w implementacji (ale mniej wydajny). Jeśli znasz tylko tablice a nie znasz std::vector, pamiętaj że tablica dla wielkości podanej w trakcie działania (nie stałej), powinna być alokowana dynamicznie przez new a zwalniana przez delete[].

Na koniec jeszcze informacja. Jeśli przykład nie byłby szkolny, użył bym po prostu algorytmu z biblioteki standardowej: https://en.cppreference.com/w/cpp/algorithm/sample lub przy algorytmie podobnym do (2), https://en.cppreference.com/w/cpp/algorithm/random_shuffle

BTW. Do kodu pytającego nie ma się co odnosić bo niewiele w nim jest a i to z podstawowymi błędami. Jeśli chcesz @Mavannkas zaimplementować któryś z tych algorytmów, to proszę  bo podany w odpowiedzi jest błędny.

komentarz 4 lutego 2019 przez Trzeci Nowicjusz (220 p.)

@Mavannkas, jak dla mnie to narazie za wysoki poziom ale sie nie poddaje smiley

komentarz 4 lutego 2019 przez Trzeci Nowicjusz (220 p.)
przywrócone 21 lutego 2019 przez Trzeci

@mokrowski, W końcu mi się udalo może to nie jest jakies profesjonalne  ale dziala i jeszcze musze dac endl 

#include <iostream>
#include <cstdlib>
#include <time.h>
using namespace std;


int main()
{


    int ile_obec,ile_nieobec,ile_uczniow;
    cout<<"Podaj liczbe obecnych uczniow: ";
    cin>>ile_obec;

    cout<<"Podaj liczbe nieobecnych uczniow: ";
    cin>>ile_nieobec;

    cout <<endl;

    if(ile_nieobec>ile_obec)
    {
        cout<<"Liczba uczniow nieobecnych nie moze byc wieksz od obecnych"<<endl<<"Podaj inna liczbe: ";
        cin>>ile_nieobec;
        cout<<endl;
    }


    ile_uczniow = ile_nieobec + ile_obec;

    int x[ile_nieobec];

    cout << "Podaj numery nieobecnych uczniow: "<<endl;

    for(int i=1; i<=ile_nieobec; i++)
    {
        cout<<"Numer "<<i<<" ";
        cin>>x[i];
        cout<<endl;

    }
    int liczba;
    srand(time(NULL));
    liczba = rand()%ile_obec+1;



    string odp;
    cout<<"Wylosowano numer "<<liczba;
    for(;;){
    cout<<endl<<"Jezeli wylosowany numer to numer nieobecny napisz |ponow| by wylosowac inny numer lub |zakoncz| by wyloczyc program ";
    cin >>odp;

    if(odp == "ponow")
    {
      srand(time(NULL));
      liczba = rand()%ile_obec+1;
      cout<<liczba;
    }
    else
    {
        exit(0);
    }
    }
    return 0;
}


PS. dam endl i musze zastąpic nie losowanie numerów nieobecnych f

komentarz 4 lutego 2019 przez Trzeci Nowicjusz (220 p.)

@mokrowski, Z góry dziękuje za pomocsmiley

komentarz 4 lutego 2019 przez Mavannkas Bywalec (2,290 p.)

@mokrowski, 

Tak dla pewności sparafrazuje te dwa przykłady na swój sposób bo nie jestem pewien czy dobrze rozumiem.

1.Na start wypełniam N-elementową tablice liczbami od 1 do n. Później podczas wczytywania nieobecnych zamieniam ich pozycja z aktualnie ostatnią [n-1,...,0] w dopiero wtedy losuje z dostępnych numerów?

2.Tu podobnie ale nie wystąpi sytuacja typu 1,2,3,23,5,6... ponieważ całość tablicy się przesunie? 

zaimplementować któryś z tych algorytmów, to proszę  bo podany w odpowiedzi jest błędny.

Mógłbym wiedzieć jeszcze dlaczego błędny? Pod względem tego co zaznaczyłeś wcześniej czy coś innego? 

Z góry bardzo dziękuję za odpowiedź i pomoc zielonemu :D 

komentarz 4 lutego 2019 przez Mavannkas Bywalec (2,290 p.)

@Trzeci, Fajne obejście problemu haha. W 50 linii masz wylonczyc zamiast wyłączyć. I zamiast if wykorzystaj switch-case

komentarz 4 lutego 2019 przez sebeks Mądrala (5,300 p.)

@mokrowski, Jak to czytałem to najpierw przyszła mi na myśl funkcja rekurencyjna, która losuje osobę z tablicy. Sprawdza czy osoba jest obecna jeśli tak to zwraca jej numer(index), a jeśli nie to wywołuje się jeszcze raz. Jednak faktycznie takie działanie może wiele razy trafiać w osobę nieobecną. Np .przypadek grypy w klasie i wielu nieobecnych uczniów. Więc przyszło mi do głowy inne rozwiązanie. Mamy tablicę osób obecnych i nieobecnych. Robimy funkcję filtrującą i najpierw wyciągamy z tej tablicy tylko osoby obecne do nowej dynamicznej tablicy, potem mierzymy długość nowej tablicy i losujemy osobę z nowej tablicy zawierającej tylko osoby obecne. Co sądzisz o takim rozwiązaniu?

komentarz 4 lutego 2019 przez mokrowski VIP (148,200 p.)

@sebeks, w proponowanym rozwiązaniu będziesz miał bardzo wiele realokacji pamięci i .. 3 tablice!

@Mavannkas, ze względu na brak determinizmu czyli to co pisałem wcześniej. Nie widzę sensu czepiania się szczegółów w kodzie... 

No dobrze... napiszę uproszczony problem i  opatrzony komentarzami... zastrzegam że to nie jest dobry styl pisania ale mam przekazać ideę:

#include <iostream>
#include <cstdlib>
#include <ctime> // Dla ew. zasiewu generatora.

int main() {
	unsigned ilosc_uczniow;
	unsigned ilosc_nieobecnych;
	unsigned indeks_szczesciarza;

	// Zasiew generatora (zresztą bardzo kiepskiego)
	// https://www.youtube.com/watch?v=LDPMpc-ENqY
	srand(0); // Tu zmieniaj liczby jeśli chcesz by wyniki były powtarzalne lub podaj time(NULL) wtedy "losowe"

	std::cout << "Podaj ilość uczniów: ";
	std::cin >> ilosc_uczniow;
	// TODO: Kontrola poprawności wprowadzonych danych...
	std::cout << "Podaj ilu uczniów jest nieobecnych: ";
	std::cin >> ilosc_nieobecnych;
	// TODO: Kontrola poprawności wprowadzonych danych...
	if (ilosc_uczniow < ilosc_nieobecnych) {
		std::cerr << "Jeśli jest więcej nieobecnych niż uczniów, kogo chcesz wylosować?\n";
		exit(EXIT_FAILURE);
	} else if (ilosc_uczniow == ilosc_nieobecnych) {
		std::cerr << "Jeśli wszyscy są nieobecni, kogo chcesz wylosować?\n";
		exit(EXIT_FAILURE);
	}

	// Dynamiczne tworzenie tabeli uczniów o podanej w trakcie działania wielkości.
	unsigned * uczniowie = new unsigned[ilosc_uczniow]; // Uwaga: jest new, powinno pod koniec programu pojawić się delete
	// Wypełnienie tabeli numerami uczniów, numer zgodny z indeksem w tabeli.
	for (unsigned i = 0; i < ilosc_uczniow; ++i) {
		uczniowie[i] = i;
	}

	// Pętla wybierania nieobecnych, losuje z zakresu zmniejszającego się po każdym wybraniu nieobecnego.
	// Nieobecny jest zamieniany z obecnym na końcu tabeli.
	for (unsigned i = 0; i < ilosc_nieobecnych; ++i) {
		// To załatwia wybór nieobecnych z malejącego zakresu.
		unsigned indeks_nieobecnego = rand() % (ilosc_uczniow - i);
		// indeks "na końcu tabeli", - 1 bo poprawne indeksy to [0, ilosc_uczniow)
		unsigned indeks_docelowy = ilosc_uczniow - i - 1;
		// Zamiana uczniów. Nieobecny wędruje na koniec tabeli, w jego miejsce wstawiany 
		// jest ten z końca.
		unsigned numer_ucznia = uczniowie[indeks_nieobecnego];
		uczniowie[indeks_nieobecnego] = uczniowie[indeks_docelowy];
		uczniowie[indeks_docelowy] = numer_ucznia;
	}

	// Po tych operacjach masz w zakresach:
	// - [0, ilosc_uczniow - ilosc_nieobecnych - 1] - obecnych uczniów
	// - [ilosc_uczniow - ilosc_nieobecnych, ilosc_uczniow - 1] - nieobecni uczniowie.
	
	// Wypisanie uczniów obecnych
	std::cout << "Obecni uczniowie   : ";
	for (unsigned i = 0; i < (ilosc_uczniow - ilosc_nieobecnych); ++i) {
		std::cout << uczniowie[i] << ' ';
	}
	std::cout << '\n';

	// Wypisanie uczniów nieobecnych
	std::cout << "Nieobecni uczniowie: ";
	for (unsigned i = ilosc_uczniow - ilosc_nieobecnych; i < ilosc_uczniow; ++i) {
		std::cout << uczniowie[i] << ' ';
	}
	std::cout << '\n';

	indeks_szczesciarza = rand() % (ilosc_uczniow - ilosc_nieobecnych);
	
	std::cout << "Szczęściarzem jest : " << uczniowie[indeks_szczesciarza] << '\n';

	delete [] uczniowie;

	return EXIT_SUCCESS;
}

 

komentarz 5 lutego 2019 przez Trzeci Nowicjusz (220 p.)

@Mavannkas,
wink

komentarz 5 lutego 2019 przez Trzeci Nowicjusz (220 p.)

@mokrowski, Wow

Podobne pytania

+1 głos
1 odpowiedź 75 wizyt
0 głosów
1 odpowiedź 159 wizyt
0 głosów
1 odpowiedź 171 wizyt

87,976 zapytań

136,557 odpowiedzi

304,510 komentarzy

58,337 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Sklep oferujący ćwiczenia JavaScript, PHP, rozmowy rekrutacyjne dla programistów i inne materiały

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...