Losowanie bez powtórzeń ze zbioru liczb z użyciem pętli

0

Witam, mam losowanie liczb z danego przedziału,
chcę dorobić by liczby były bez powtórzeń w każdej kolejnej pętli
dodam że pętla wykonuje się 20 razy(main)

 
    void wczytaj(){                            //-------------- WCZYTYWANIE PLIKU - id kategorii
   		fstream plik;
    	plik.open(nazwaPliku,ios::in);                             //plik tekstowy 
           		if(plik.good()==false){
   			cout<<"Nie udalo sie otworzyc pliku!";           //brak pliku
      		exit(0);
   		}


    	cout<<"--------------------------------------------------------------"<<endl;  
    	int aktualny_nr=1;
    	string linia;
 
  		#define ARR_SIZE 20
    	int arr[ARR_SIZE] = {1,7,13,19,25,31,37,43,49,55,61,67,73,79,85,91,97,103,109,115};         ////LOSOWANIE PYTAŃ Z KATEGORII
                                                            //numery oznaczają pole gdzie znajduje się początek-->pytanie + 4odpowiedzi do wyboru +poprawna
    
    	int nr_linii = arr[rand()%ARR_SIZE];
 
    	while(getline(plik,linia)){
      		if(aktualny_nr==nr_linii) tresc=linia;
      		if(aktualny_nr==nr_linii+1) a=linia;
      		if(aktualny_nr==nr_linii+2) b=linia;
      		if(aktualny_nr==nr_linii+3) c=linia;
      		if(aktualny_nr==nr_linii+4) d=linia;
      		if(aktualny_nr==nr_linii+5) poprawna=linia;
      		if(aktualny_nr==nr_linii+6) tresc=linia;
      		aktualny_nr++;
   		}

   		plik.close();

	}
.........
	pytania s1[20];
   		int suma=0;
   		for(int i=0; i<=19; i++){
   			s1[i].ustawKategorie(numer_kategoria);
      		s1[i].nr_pytania=i+1;
      		s1[i].wczytaj();
      		s1[i].zadaj();
      		s1[i].sprawdz();
      		suma+=s1[i].punkt;                     //sumowanie punktow(pętla)
  		}
0

Możesz do tego użyć kontenera std::set, kasując już wylosowane elementy. Nie wiem czy to jest najbardziej wydajne rozwiązanie, ale wydaje się być bardzo czytelne i proste do zrozumienia.

Przykładowy kod:

#include <cstdlib>
#include <ctime>

#include <algorithm>
#include <deque>
#include <iomanip>
#include <iostream>
#include <map>
#include <random>
#include <set>
#include <sstream>
#include <string>
#include <utility>

using namespace std;

#define DBG(x) { cout << left << setw(40) << #x << (x) << endl; }

class LosowanieBezPowtorzen
{
public:
	LosowanieBezPowtorzen(std::set<int> wartosci) : wartosci_(move(wartosci)) {}

	LosowanieBezPowtorzen(initializer_list<int> l) : wartosci_(l) {}

	template<typename Gen>
	int losuj(Gen&& gen){
		if(wartosci_.size() == 0)
			throw out_of_range("Skonczyly sie wartosci do losowania");

		uniform_int_distribution<int> dis(0,wartosci_.size()-1);
		auto it = begin(wartosci_);
		advance(it,dis(gen));
		int ret = *it;
		wartosci_.erase(it);
		return ret;
	}

private:

	std::set<int> wartosci_;
};

int main()
{
	mt19937_64 gen(random_device{}());

	LosowanieBezPowtorzen l{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25};

	for(int i = 0; i < 20; i++){
		DBG(l.losuj(gen));
	}
}

Przykład działania: http://ideone.com/MICnKy

4

Ojej, masakra.

Ja proponuję http://www.cplusplus.com/reference/algorithm/random_shuffle/

Zajmie w najgorszym razie dwie linijki.

3

Ja proponuję coś takiego jak dużo razy @_13th_Dragon podawał.

const int iloscWartosci = 20;
int doWylosowania = 7;
int wartosci[iloscWartosci];
for(int i = 0; i<iloscWartosci;++i) wartosci[i] = i;
for(int i = 0; i<doWylosowania;++i) swap(wartosci[i], wartosci[rand()%(doWylosowania-i)+i]);
for(int i = 0; i<doWylosowania;++i) cout << wartosci[i] << ' ';

Oczywiście można to ładniej opakować, ale ma to ilustrować jedynie algorytm.

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