Witam wszystkich. Pierwszym postem związanym z tematyką naszego bloga, będzie dawno temu zapomniany projekt z programowania strukturalnego.
Postanowiłem go tu umieścić ponieważ w mojej opinii stanowi on ciekawe zagadnienie algorytmiczne jak i programistyczne. Do rzeczy…
W okręgu umieszczonych jest n obiektów, następnie eliminowany jest co k-ty obiekt, aż pozostanie tylko jeden. Problem polega na wskazaniu tego obiektu, który pozostanie.
Nazwa nawiązuje do postaci historyka Józefa Flawiusza, który w trakcie wojny rzymskorzydowskiej został, wraz z grupą 40 żydowskich powstańców (czyli razem 41 osób), otoczony przez Rzymian w jaskini. Powstańcy od pojmania woleli samobójstwo, dlatego też zdecydowali się utworzyć krąg i zabijać co trzecią osobę, aż zostanie tylko jedna, która popełni samobójstwo. Flawiusz chcąc uniknąć śmierci wyliczył, w którym miejscu powinien stanąć. Ustawił się na miejscu 16., dzięki czemu pozostał, jako przedostatnia osoba, przy życiu. Następnie, wraz z osobą z numerem 31., oddał się w ręce Rzymian i przeżył.
Pisząc ten program postawiłem pewne wymagania -użytkownik programu może podać liczbę straceńców, skok(co który), oraz od którego egzekucja ma się zacząć. Wymusiło to potrzebę korzystania z dynamicznych struktur danych:
int *starcency=malloc(N*(sizeof (int)));
Skutkiem tego jest to, iż kompilator nie musi znać stałych przed kompilacją. Poprawia to szybkość algorytmu, ułatwia pracę nad kodem i jest zgodne z „duchem C” (mimo, że program został napisany z naciskiem na wydajność a nie na estetykę – to nie ASP).
Omawiając po kolei strukturę kodu możemy zauważyć funkcję:
void show_array(int tab[], int N) { int i; for(i=0; i<N; i++) printf("%d,", tab[i]); return; }
Jest ona odpowiedzialna za przedstawienie naszych straceńców w formie tablicy. Kolejnym blokiem na jaki natrafiamy jest funkcja sprawdzająca kiedy nasz algorytm należy zatrzymać.
int czy_sa_zywe(int tab[], int N) { int i; for(i=0; i<N; i++) { if(tab[i]!=0) return 1; } return 0; }
Ostatnim a za razem najbardziej interesującym blokiem jest główna funkcja main.
int main () { int start; int N; int M; printf("Podaj ilosc stracencow:\t "); scanf("%d",&N); printf("Podaj co ktorego:\t "); scanf("%d",&M); printf("Od ktorego:\t "); scanf("%d",&start); info(); int i; int *starcency=malloc(N*(sizeof (int))); for(i=0;i<N;++i) starcency[i]=i+1; show_array(starcency,N); int licznik = start; int a = 0; while(czy_sa_zywe(starcency,N)) { if(starcency[licznik]!=0) { if(licznik<N) { starcency[licznik]=0; printf("\n\nStracenie nr. %d Zabity nr: %d\n\n",++a,licznik+1); show_array(starcency,N); licznik+=M; } else { licznik = licznik%N; } } else{ licznik++; } } free(starcency); return 0; }
Następne linijki pokazują dynamikę tablic i zastosowanie wskaźników:
for(i=0;i<N;++i) starcency[i]=i+1;
W tej pętli for widzimy, że i jest zwiększane o jeden. Jest to wymuszone tym, iż tablice są numerowane od liczby 0. Idąc dalej natrafiamy na pętlę while, zagnieżdżenie if oraz else. Są one odpowiedzialne z warunkowość naszego programu.
A teraz trochę pogderam o tym co wszystkim zazwyczaj wisi… Mowa tu o optymalności kodu. W dobie dzisiejszego sprzętu mało kto widział napis bad_alloc. I nie mówię tu o takich psujach jak jak :3
W opisie zadania projektowego wskazano na wydajność algorytmu. Dostosowałem się do tej uwagi. Do programu zamieszczam również dodatkowy program pokazujący ilość przebiegów pętli w funkcji main. Początkowe wersje programu wykazywały ok. 600 obiegów a ostatnia (przy tych samych danych wejściowych) nieco ponad 100.
Podsumowując:
Program nie działa w momencie podania mu znaku innego niż liczba jako daną wejściową oraz w memencie podania liczby ujemnej. Kolejnym ograniczeniem jest ilość pamięci RAM. Przy liczbach dużych (rzędu 107 skazańców) system zabija program.
Pracując nad tym projektem niewiele informacji znalazłem o algorytmice tego problemu. W związku z tym będę wdzięczny za wszelkie słowa krytyki. Mam nadzieję, że post ten wniósł coś ciekawego. Zachęcam do obserwowania „świeżego” blogu.
Kod całościowy:
//Radoslaw Sakowicz //www.uengineering.net #include<stdio.h> #include<stdlib.h> #include<math.h> void info() { printf("\n\nRadoslaw Sakowicz\n"); printf("Wariacja na temat problemu Jozefa Flawiusza.\n\n\n"); } void show_array(int tab[], int N) { int i; for(i=0; i<N; i++) printf("%d,", tab[i]); return; } int czy_sa_zywe(int tab[], int N) { int i; for(i=0; i<N; i++) { if(tab[i]!=0) return 1; // zywe } return 0; //nie na zywych } int main () { unsigned long long int q = 0; int start; int N; int M; printf("Podaj ilosc stracencow:\t "); scanf("%d",&N); printf("Podaj co ktorego:\t "); scanf("%d",&M); printf("Od ktorego:\t "); scanf("%d",&start); info(); int i; int *starcency=malloc(N*(sizeof (int))); for(i=0;i<N;++i) starcency[i]=i+1; show_array(starcency,N); int licznik = start; int a = 0; while(czy_sa_zywe(starcency,N)) { q++; if(starcency[licznik]!=0) { if(licznik<N) { starcency[licznik]=0; printf("\n\nstracenie nr. %d zabity nr: %d\n\n",++a,licznik+1); show_array(starcency,N); licznik+=M; } else { licznik = licznik%N; } } else{ licznik++; } } printf("\n\nIlosc obiegow petli: %d",q); free(*starcency); return 0; }
Nie… Nie pisałem apki w WPFie 😛 Ale znam takiego, który jest magikiem Javy i szczyci się umiejętnością pisania apek w WPFie przy kobietach. Dzięki za głos krytyki. Błędy zarówno w kodzie jak i gramatyczno-językowe zostały poprawione.