Əvvəlcə bizdə \{1, 2, ..., n\} massivi var. Sonra qarışdırma (tasovka) prosedurası yerinə yetirilir. Bizə son yerdəyişmə (permutasiya) verilib. Prosedur yerinə yetirildikdən sonra məhz onu əldə etmək ehtimalını tapmaq lazımdır.
Axtarılan ehtimal bərabərdir:
Qarışdırmanın hər addımında bir ədədi seçilir. ədədinin seçilmə variantlarının sayı -ə bərabərdir. Qarışdırma addımlarının sayı da -dir. Deməli, n^n seçim ardıcıllığı mövcuddur. Qeyd edək ki, müxtəlif seçim ardıcıllıqları eyni yekun yerdəyişməyə gətirib çıxara bilər. Çünki n^n sayı -dan xeyli böyükdür.
massivinə \{1, 2, ..., n\} ardıcıllığını yazaq. -da bütün mümkün qarışdırma proseslərini (1 \le r_i \le n) modelləşdirərək, bütün mümkün seçim variantlarını (r_1, r_2, ..., r_n) perebor edəcəyik. Qeyd edək ki, r_1, r_2, ..., r_n ədədlərinin sabitlənmiş ardıcıllığı hər addımda məhz hansı mübadilələrin yerinə yetiriləcəyini, deməli, prosedur bitdikdən sonrakı yekun massivi də birmənalı olaraq müəyyən edir. Əgər bütün mübadilələr tətbiq edildikdən sonra massivini əldə etmişiksə, cəhdi uğurlu hesab edirik. Tutaq ki, belə cəhdlər ədəd alındı. Onda axtarılan ehtimal bərabərdir:
Qarışdırma prosesinin bütün mümkün davamlarını rekursiv şəkildə perebor edən və onlardan neçəsinin hədəf yerdəyişməsinə gətirdiyini hesablayan shuffle funksiyasını reallaşdıraq.
Funksiyanın bir parametri var: — cari iterasiyanın nömrəsi (-dan başlayır). Bu o deməkdir ki, ilk mübadilə artıq yerinə yetirilib, massivi isə bu əməliyyatlardan sonra alınan vəziyyəti saxlayır.
Vaxt məhdudiyyətinə uyğunlaşmaq üçün aşağıdakı kəsmədən (отсечение) istifadə edəcəyik. Tutaq ki, nömrəli iterasiya yerinə yetirilir və cari massivi hədəf massivindən pozisiyada fərqlənir. Hələ n - pos mübadilə yerinə yetirilməlidir. Qeyd edək ki, bir mübadilə ilə ən çoxu iki elementi öz yerinə qoymaq olar. Deməli, qalan addımlar ərzində cəmi maksimum 2 \cdot (n - pos) pozisiyanı düzəltmək mümkündür.
Əgər diff \textgreater 2 \cdot (n - pos) olarsa, onda -dan massivini artıq əldə etmək mümkün deyil. Bu halda sonrakı perebora ehtiyac yoxdur və rekursiyanın cari budağını dərhal dayandırmaq olar.
Alqoritmin realizasiyası
İşçi massivləri elan edək:
— verilmiş yerdəyişməsi;
— perebor zamanı cari yerdəyişmə;
int a[10], cur[10];shuffle funksiyası qarışdırma prosesinin bütün mümkün davamlarını rekursiv şəkildə perebor edərək, onlardan neçəsinin hədəf yerdəyişməsinə gətirəcəyini hesablayır.
void shuffle(int pos)
{Bütün əməliyyat yerinə yetirilib. Yalnız yoxlamaq qalır — əldə edilmiş massivi tələb olunan ilə üst-üstə düşürmü. Əgər düşürsə, deməli, daha bir uğurlu ssenari tapılıb. Bu halda -u artırırıq.
if (pos == n)
{
for (int i = 0; i \textless n; i++)
if (cur[i] != a[i]) return;
countGood++;
return;
}dəyişənində cari massivinin tələb olunan -dan neçə pozisiyada fərqləndiyini hesablayırıq.
int diff = 0;
for (int i = 0; i \textless n; i++)
if (cur[i] != a[i]) diff++;Hazırda bizə n - pos addım yerinə yetirmək qalır. Bir mübadilə ilə maksimum iki yanlış pozisiyanı düzəltmək olar. Əgər artıq hazırda fərqlərin sayı bundan çoxdursa, rekursiyanı davam etdirməyin mənası yoxdur.
Sadəcə peреborun bu budağına baxmağı dayandırırıq.
if (diff \textgreater 2 * (n - pos)) return;-in bütün mümkün qiymətlərini perebor edirik.
for (int r = 0; r \textless n; r++)
{
swap(cur[pos], cur[r]);
shuffle(pos + 1);
swap(cur[pos], cur[r]);
}
}Proqramın əsas hissəsi. ədədini — massivinin ölçüsünü oxuyuruq.
while (scanf("%d", \&n) == 1)
{Giriş massivini oxuyuruq. Modelləşdirmə həmişə \{1, 2, ..., n\} massivindən başlayır. Onu da -a yazırıq.
for (int i = 0; i \textless n; i++)
{
scanf("%d", \&a[i]);
cur[i] = i + 1;
}Pereboru işə salırıq. dəyişənində hansı say təsadüfi seçim ardıcıllıqlarının massivinə gətirdiyini hesablayırıq.
countGood = 0;
shuffle(0);Cavabı hesablayıb çap edirik.
res = countGood / pow(n, n);
printf("%.6lf\n", res);
}