13. MEŠALICA - rešenje
13. MEŠALICA - rešenje
Ovaj zadatak zahteva simulaciju mešanja niza više puta.
Na ulazu se daje permutacija niza 0, 1, 2, ..., n-1 nakon jednog mešanja i broj m koliko puta treba izvršiti mešanje.
Cilj je da se odredi krajnji niz posle m mešanja.
Prvi prikaz rešenja koristi algoritam grube sile, gde se mešanje ponavlja m puta.
#include <iostream>
#include <vector>
#include <fstream> // dodatak za čitanje iz datoteke, opciono
#define DATOTEKA "01.in" // opciono za testiranje sa fajlom
using namespace std;
// Funkcija za ispis elemenata vektora
void ispisi(vector<int>& v)
{
for(vector<int>::iterator it = v.begin(); it != v.end(); ++it)
{
cout << (*it) << " ";
}
// cout << endl; // po potrebi novi red na kraju ispisa
}
int main()
{
// Opciono za čitanje iz datoteke
/*
fstream dataFile;
dataFile.open(DATOTEKA);
if (dataFile.fail())
{
cerr << "Error reading data!" << endl;
system("PAUSE");
return 1;
}
*/
int n; // veličina niza
long long m; // broj ponavljanja mešanja
cin >> n >> m; // za standardni ulaz
// dataFile >> n >> m; // za čitanje iz datoteke
vector<int> niz; // originalni niz
vector<int> niz2(n); // privremeni niz za skladištenje novog rasporeda
vector<int> shema(n); // šema mešanja: pozicija gde ide svaki element
// Učitavanje permutacije i formiranje šeme
for(int i = 0; i < n; i++)
{
int a;
cin >> a; // za standardni ulaz
// dataFile >> a; // za čitanje iz datoteke
niz.push_back(a); // dodajemo element u originalni niz
shema[a] = i; // beležimo gde element 'a' ide nakon mešanja
}
// dataFile.close(); // zatvaranje datoteke ako je korišćena
// Grubo ponavljanje mešanja m puta
for(int i = 1; i < m; i++)
{
vector<int> niz2(n); // inicijalizacija privremenog niza
for(int j = 0; j < n; j++)
{
int pozN = shema[j]; // nova pozicija elementa j prema šemi
int s = niz[j]; // element koji treba premeštati
niz2[pozN] = s; // stavljamo element na novu poziciju
}
niz = niz2; // ažuriramo originalni niz posle jednog mešanja
}
// Ispis konačnog niza
ispisi(niz);
return 0;
}
Komentar:
Ovo rešenje radi tačno, ali je efikasno samo za male vrednosti m, jer u svakoj iteraciji ponavlja mešanje celog niza. Za velike m (npr. 1018) potrebno je primeniti optimizovani pristup koristeći algoritam brzog stepenovanja permutacije.
13. MEŠALICA - rešenje pomoću algoritma brzog stepenovanja
Za velike vrednosti m (npr. 1018) grubo ponavljanje nije praktično.
Optimizovano rešenje koristi algoritam brzog stepenovanja primenjen na permutacije.
Ideja je da transformaciju niza "stepenujemo" koristeći binarni pristup, slično kao kod Xn u matematici.
#include <iostream>
#include <vector>
#include <fstream> // opciono za čitanje iz fajla
#define DATOTEKA "01.in"
using namespace std;
// Funkcija za ispis elemenata vektora
void ispisi(vector<int>& v)
{
for(vector<int>::iterator it = v.begin(); it != v.end(); ++it)
{
cout << (*it) << " ";
}
// cout << endl; // po potrebi novi red
}
int main()
{
int n; // veličina niza
long long m; // broj ponavljanja mešanja
cin >> n >> m;
vector<int> niz; // originalni niz
vector<int> shema(n); // šema mešanja
// Učitavanje permutacije i formiranje šeme
for(int i = 0; i < n; i++)
{
int a;
cin >> a;
niz.push_back(a);
shema[a] = i; // pozicija elementa a posle jednog mešanja
}
// Ako je m = 1, dovoljno je ispisati originalni niz
if(m == 1)
{
ispisi(niz);
return 0;
}
m = m - 1; // smanjenje jer smo već učitali prvo mešanje
while(m >= 1)
{
vector<int> niz2(n); // privremeni niz
for(int j = 0; j < n; j++)
{
int pozN;
if(m % 2 == 1) // ako je trenutni eksponent neparan
{
pozN = shema[j]; // nova pozicija elementa
int s = niz[j]; // element koji se premesta
niz2[pozN] = s;
}
else // ako je trenutni eksponent paran
{
pozN = shema[j];
int s = shema[pozN]; // "stepenovanje" šeme
niz2[j] = s;
}
}
if(m == 1) // ako smo došli do poslednjeg koraka
{
ispisi(niz2);
return 0;
}
else if(m % 2 == 1) // neparan eksponent
{
niz = niz2; // ažuriramo niz
m--; // smanjujemo eksponent
}
else // paran eksponent
{
shema = niz2; // ažuriramo šemu
m /= 2; // delimo eksponent na pola
}
}
ispisi(niz2); // konačan ispis
return 0;
}
Komentar i analiza:
- Ovaj pristup koristi logiku brzog stepenovanja: eksponent se deli binarno, što omogućava efikasno računanje niza posle
mmešanja. - Operacije se sprovode ili na samom nizu (ako je eksponent neparan) ili na šemi (ako je paran), čime se izbegava direktno ponavljanje m puta.
- Kompleksnost je O(n log m), što je dramatično brže od grube sile za velike
m. - Kod je modularan i lako ga je proširiti za različite permutacije ili dodatne operacije nad nizom.
Moguća poboljšanja:
- Bolje imenovanje promenljivih radi čitljivosti (npr.
privremeniNiz,novaPozicija). - Dodavanje funkcije za brzo stepenovanje permutacije radi modularnosti i ponovne upotrebe.
- Uklanjanje opcionalnog čitanja iz fajla ako se ne koristi.
- Dodavanje komentara koji objašnjavaju binarni pristup i manipulaciju šemom za početnike.