Kürəklə edilən hiylə çörəklərin aşağıdakı yerdəyişməsini yerinə yetirir:
Onu qonşu elementlərin iki yerdəyişməsi şəklində təsvir etmək olar:
Qonşu elementlərin hər bir yerdəyişməsi permutasiyanın cütlüyünü dəyişir. Deməli, çörəklər üzərində göstərilən əməliyyat permutasiyanın cütlüyünü saxlayır.
Çörəyi Maykl-in rəisinin tələb etdiyi kimi sıralamaq yalnız o halda mümkündür ki, permutasiyaların cütlükləri üst-üstə düşsün.
Məsələnin xətti həlli onun üzərində qurulub ki, iki permutasiya eyni cütlüyə malikdir yalnız və yalnız onların ayrıldığı tsikllərin sayının cütlüyü üst-üstə düşdükdə.
Lemma. Permutasiyalar nəzəriyyəsinin aşağıdakı faktına baxaq:
Buna görə də cütlüyü yoxlamaq üçün:
permutasiyanı tsikllərə ayırmaq;
onların sayını hesablamaq lazımdır.
Əgər iki permutasiyanın tsikl sayının cütlüyü eynidirsə, onların cütlükləri üst-üstə düşür.
Bu, intuitiv olaraq ondan irəli gəlir ki, uzunluğunda hər bir tsikli elementlərin k - 1 dəyişməsindən yığmaq olar, ona görə də ümumi dəyişmələrin sayı bərabərdir
Nümunə
Birinci nümunədə birinci permutasiya inversiya, ikincisi isə — inversiya ehtiva edir. Hər iki permutasiyadakı inversiyaların sayı eyni cütlüyə malikdir.
Permutasiyaları tsikllərə ayıraq:
(1, 3, 4, 2) = (1) (3, 4, 2);
(4, 3, 2, 1) = (4, 1) (3, 2);
Hər iki permutasiya iki tsikldən ibarətdir, yəni onlardakı tsikllərin sayı da eyni cütlüyə malikdir.
İkinci nümunədə birinci permutasiya inversiya, ikincisi isə — inversiya ehtiva edir. Bu permutasiyalardakı inversiyaların sayı fərqli cütlüyə malikdir.
Permutasiyaları tsikllərə ayıraq:
(1, 2, 3, 4, 5, 6) = (1) (2) (3) (4) (5) (6);
(6, 5, 4, 3, 2, 1) = (6, 1) (5, 2) (4, 3);
Birinci permutasiya tsikldən, ikincisi isə — tsikldən ibarətdir. Beləliklə, bu permutasiyalardakı tsikllərin sayının cütlüyü fərqlidir.
Alqoritmin realizasiyası
Permutasiyanı saxlamaq üçün massiv elan edək.
#define MAX 100010
int a[MAX];run funksiyası indeksindən başlayaraq permutasiyanın bir tsiklindən keçir. Hər addımda o, pos \to a[pos] qaydası ilə tsiklin növbəti elementinə keçir. Ziyarət edilmiş elementlər onları təkrar emal etməmək üçün qiyməti ilə işarələnir. Beləliklə, funksiya permutasiyanın bir tsiklini tam gəzir və onun bütün elementlərini artıq ziyarət edilmiş kimi qeyd edir.
void run(int pos)
{
int v;
while (a[pos] != -1)
{
v = a[pos];
a[pos] = -1;
pos = v;
}
}parity funksiyası permutasiyasındakı tsikllərin sayının cütlüyünü hesablayır, yəni tsikllərin sayını -yə görə modul ilə qaytarır. Funksiya massivin bütün mövqelərini ardıcıl olaraq nəzərdən keçirir.
int parity(int *a)
{
int res = 0;Massivin bütün mövqelərini ardıcıl olaraq nəzərdən keçiririk.
for (int i = 0; i < n; i++)Əgər element hələ ziyarət edilməyibsə (a[i] \ne -1), bu, yeni tsiklin başlanğıcı deməkdir. Bu halda funksiyası çağırılır, o, bütün tsikli gəzir və onun elementlərini qiyməti ilə işarələyir.
if (a[i] != -1)
{
run(i);Tsikl gəzildikdən sonra sayğacı artırılır.
res++;
}Tsikllərin sayının cütlüyünü qaytarırıq.
return res % 2;
}Proqramın əsas hissəsi. Birinci permutasiyanı oxuyuruq. Oxuma zamanı elementlərin nömrələnməsindən işləmək üçün daha rahat olan 0 .. n - 1 nömrələnməsinə keçmək üçün hər bir qiymət azaldılır (a[i]--).
scanf("%d",&n);
for (i = 0; i < n; i++)
scanf("%d",&a[i]), a[i]--;dəyişənində permutasiyasındakı tsikllərin sayının cütlüyünü hesablayırıq.
p1 = parity(a);İkinci permutasiyanı oxuyuruq. dəyişənində permutasiyasındakı tsikllərin sayının cütlüyünü hesablayırıq.
for (i = 0; i < n; i++)
scanf("%d",&a[i]), a[i]--;
p2 = parity(a);İki permutasiyadakı tsikllərin sayının cütlüklərini müqayisə edirik və cavabı çap edirik.
if (p1 == p2) printf("Possible\n");
else printf("Impossible\n");