• 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.

VPS Starter Arubacloud
0 głosów
1,326 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 Mędrzec (155,460 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 Mędrzec (155,460 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 Mędrzec (155,460 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 Mędrzec (155,460 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ź 116 wizyt
0 głosów
1 odpowiedź 538 wizyt
0 głosów
1 odpowiedź 305 wizyt

92,453 zapytań

141,262 odpowiedzi

319,087 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

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

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...