Algorytm Liczba-Inwersji (algorytm Ryttera)

0

NiechP[0..n-1] będzie permutacją liczb0,\ 1,\ 2\ ..n-1zadaną tablicą o zakresie [0..n-1].
Na przykład mamy 15 inwersji w permutacji
P[0..6]\ =\ [5,\ 4,\ 3,\ 6,\ 0,\ 1,\ 2]

Pomocniczą tablicą będzie Licz[0..n], załóżmy że początkowo zawiera ona same zera.
Funkcja logiczna odd() sprawdza czy liczba jest nieparzysta. Funkcjadiv jest dzieleniem całkowitoliczbowym, pomijamy resztę.
Funkcja\log n zwraca całkowitoliczbową część logarytmu przy podstawie2, np.\log 1025\ =\ 10.

Końcową wartością zmiennej wynik jest liczba inwersji permutacji P.

1 wynik:=0;

2 repeat\log n times

3 fori:=0 to n-1 do

4 if odd(P[i]) then Licz[P[i]]:=Licz[P[i]]+1

5 else wynik:=wynik+Licz[P[i]+1];

6 fori=0 ton-1 do

7 Licz[i]:=0; P[i]:=P[i]\ div\ 2

Mam ten problem że nie wiem czy algorytm jest poprawny bo dla np.3,2,1 są 3 inwersje a jak liczę tym algorytmem to mi wychodzi 1

liczę tak że dla i=0 licz[3]=1
i=1 wynik=licz[2+1]=1
i=2 licz[2]=1

czyli wynik 1 a powinno być 3...

Proszę o pomoc

0

Wygląda na to, że repeat działa 1 raz a powinien 2. Tak samo w przypadku podanych wyżej 7 liczb, pętla działa o 1 raz za mało. Nie doszukałem się 'oryginalnego' algorytmu w sieci, tylko na tej stronie z której Ty korzystałeś i rzeczywiście jest tam 'całkowitoliczbowa część logarytmu' a bardziej wygląda to na zaokrąglenie. Proponuję poszukać bezpośrednio u Ryttera.

0

(3,2,1) ** nie jest** permutacją dla algorytmu Ryttera. Sprawdź co dostaniesz dla permutacji (2,1,0).

0
bogdans napisał(a):

(3,2,1) ** nie jest** permutacją dla algorytmu Ryttera. Sprawdź co dostaniesz dla permutacji (2,1,0).

Dla tej permutacji dostałem 1. Poza tym, tak jak wspomniałem wyżej dla (5,4,3,6,0,1,2) też dostaję niepoprawny wynik.

0

tu: http://smurf.mimuw.edu.pl/node/287
jest błąd jest w opisie ile ma się razy wykonywać pętla z log n.
Zwiększ iterację o 1 i zadziała.
Chodzi o to by na końcu p ma zawierać same zera, a o tym decyduje największa liczba w ciągu równa n-1.
Czyli jeśli masz permutację o długości 4 to największa liczba w tej permutacji to 3, którą trzeba podzielić przez 2 dwa razy
dla długości 5 największa liczba to to 4, którą trzeba podzielić przez 2 trzy razy.
czyli powinno być reapeat log(n-1) +1 times

1

Ja na poprawne rozwiązanie wpadłem przypadkiem, nie chciało mi się liczyć na kartce, więc zaimplementowałem opisany w pierwszym poście algorytm. W implementacji zrobiłem błąd, i ta "błędna" implementacja daje poprawne wyniki. Błąd, to

for(int step=1;step<=log(n + 1);step++)

zamiast podanego w opisie

for(int step=1;step<=log(n);step++)

Przy okazji, wymaganą funkcję log można napisać bez użycia liczb zmiennoprzecinkowych.

    int log(int n)
    {
        int power = 1;
        int result = 0;
        while(power*2 <= n)
        {
            power*=2;
            result++;
        }
        return result;
    }
1
bogdans napisał(a):

Przy okazji, wymaganą funkcję log można napisać bez użycia liczb zmiennoprzecinkowych.

    int log(int n)
    {
        int power = 1;
        int result = 0;
        while(power*2 <= n)
        {
            power*=2;
            result++;
        }
        return result;
    }
nt RoundDownBinLog(int x)
{
	int result = 0;
	while (x>>=1)
		++result;
	return result;
}

http://ideone.com/3lmTHK

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