Zadania

  • October 2019
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View Zadania as PDF for free.

More details

  • Words: 12,371
  • Pages: 66
Zadania z Programowania I w języku C++ w środowisku systemu Linux z dnia 27 grudnia 2005

Środowisko pracy. Program make. Edytor emacs. Debugger ddd. Zad. 1. Dokonaj kompilacji pliku źródłowego hello.cc1 do pliku z programem binarnym hello. Uruchom program. Zad. 2. Dokonaj kompilacji pliku żródłowego hello.cc do pliku hello.o, a następnie do pliku hello. Uruchom program. Zad. 3. Dokonaj kompilacji plików źródłowych main.cc i fun.c w celu otrzymania programu main. Uruchom program. Zad. 4. Napisz plik Makefile z jawnymi zasadami kompilacji programów hello i main. Dodatkowo zdefiniuj regułę clean usuwającą wszystkie pliki pośrednie .o oraz wynikowe (hello i main). Zad. 5. Napisz plik Makefile2 z domyślnymi zasadami kompilacji programów w językach C i C++. Następnie korzystając z tych zasad dopisz reguły związane z przygotowaniem programów hello i main. Zad. 6. Wykorzystując predefiniowane reguły kompilacji napisz plik Makefile3 przygotowujący programy hello i main w sposób wymagany dla śledzenia ich pracy debuggerem. Zad. 7. Na przykładzie programów hello, main i pierwsze porównaj jakość kodu (rozmiar, szybkość wykonania) wygenerowanego przez kompilator z opcją -O0 i -O2. Dla pomiaru czasu skorzystaj z polecenia time. Zad. 8. Dokonaj kompilacji programów hello, main i pierwsze z poziomu edytora emacs. Zad. 9. Przy pomocy debuggera ddd prześledź wykonanie programów hello, main i pierwsze. W programie pierwsze zatrzymaj wykonanie dla 17 obliczonej liczby pierwszej, a następnie odczytaj wartości zmiennych i i j. Operacje wejścia/wyjścia Zad. 10. Korzystając ze stałej M_PI zdefiniowanej w pliku nagłówkowym cmath napisz program pi wypisujący do standardowego strumienia wyjściowego 5 kolejnych potęg liczby π z dokładnością liczby cyfr po przecinku równą wykładnikowi potęgi 1

Wersje źródłowe programów dostępne są w katalogu ~pablo/progs.

1

potęga wartość ---------------1 3.1 2 9.87 3 31.006 4 97.4091 5 306.01968

Przygotuj dwie werjse rozwiązania: pierwszą w oparciu o funkcję printf charakterystyczną dla języka C i drugą korzystającą z biblioteki iostream języka C++. Zad. 11. Napisz program liczby odczytujący ze standardowego strumienia wejściowego dwie liczby całkowite (int) i zapisujący do standardowego strumienia wyjściowego wartości odczytanych liczb, ich iloraz i sumę. Sprawdź działanie programu dla następujących danych wejściowych • 1, 3 • 2, 0 • 3, 1.5 • 7, a Następnie dokonaj zmiany odczytywanych liczb na rzeczywiste (double) i ponownie sprawdź działanie programu. Zad. 12. Począwszy od bieżącego semestru nasz wydziałowy barek wprowadził nowy sposób obsługi dla klientów będących studentami zapisanymi w systemie USOS. Barek udziela kredytu, pod warunkiem, że osoba zamówi dokładnie 3 rzeczy. W celu rozliczenia przesyła następnie studentowi maila z rachunkiem, np. w pliku rachunek.txt kanapka: 2.50 szarlotka: 1.50 woda mineralna: 1.50

Treść listu składa się zawsze z 3 wierszy. Każdy wiersz zawiera nazwę towaru, dwukropek, cenę w złotych. Nazwa towaru może się składać z dowolnej liczby słów oddzielonych odstępami, a słowa wyłącznie z liter. Napisz program suma obliczający całkowitą należność do zapłaty. Podaj dwa rozwiązania: pierwsze charakterystyczne dla języka C, drugie dla języka C++. % ./suma < rachunek.txt 2.50+1.50+1.50=5.50

2

Zad. 13. Plik 2pi.txt zawiera dwa wiersze. W każdym wierszu zapisana jest wyłącznie wartość liczby π z losowo wybraną liczbą cyfr po przecinku ∈ h100, ∞). Napisz program zamiana, który zamieni kolejność tych liczb w pliku. Podaj dwa rozwiązania: pierwsze charakterystyczne dla języka C, drugie dla języka C++. Instrukcje warunkowe i iteracje Zad. 14. Napisz program znaczace sprawdzajacy liczbę cyfr znaczących typów float i double. P Wskazówka: obliczaj sumę i=0 101 i . Zad. 15. Napisz program kwadraty obliczający sumę 100 X 000 000 i=1

1 i2

Dokonaj sumowania w kolejności 1 1 1 1 + 2 + 2 + ... + 2 1 2 3 100 000 0002 oraz w kolejności odwrotnej 1 1 1 + + ... 2 2 2 100 000 000 99 999 999 1 Obliczenia przeprowadź posługując się zmiennymi typu • float • double Wytłumacz różnice. Który z wyników jest najbliższy prawdzie? P 1 π2 Wskazówka: ∞ i=1 i2 = 6 Zad. 16. Napisz program anagram, który odczytuję nazwę pliku podaną przez użytkownika, a następnie odwraca kolejność bajtów w tym pliku. % ./anagram Podaj nazwę pliku a.txt %

Zad. 17. Korzystając z instrukcji iteracyjnych napisz program pi3 wypisujący w kolejnych wierszach wartość π z dokładnością do i miejsc po przecinku. 3

3.1 3.14 3.141 3.1415 3.14159

Zad. 18. Korzystając z instrukcji iteracyjnych napisz program pi4 wypisujący w kolejnych wierszach wartość π i z dokładnością do i miejsc po przecinku. potęga wartość ---------------1 3.1 2 9.87 3 31.006 4 97.4091 5 306.01968

Zad. 19. Napisz program tworzący zadany rysunek. Warunek: instrukcję wypisującą znak (np. *) lub liczbę w tabelce można użyć tylko jeden raz. • ********** ** * * * * * * * * * * * * * * * * * * * * ** **********

• ------------------------| 1 | 2 | 3 | 4 | ------------------------| 2 | 4 | 6 | 8 | ------------------------| 3 | 6 | 9 | 12 | ------------------------| 4 | 8 | 12 | 16 | -------------------------

Zad. 20. Napisz program slowa odczytujący liczbę słów ze strumienia wejściowego i wypisujący ich liczbę oraz średnią długość. Obliczenia przeprowadź dla tekstów Pana Tadeusza i Hamleta.2 2

Teksty utworów dostępne są w plikach ~pablo/pt.txt i ~pablo/h.txt.

4

Zad. 21. Napisz program licz będące odpowiednikiem systemowego polecenia wc, zliczającego liczbę znaków, słów i wierszy w standardowym strumieniu wejściowym. Działanie programu sprawdź na jego pliku źródłowym licz.cc i porównaj z programem wc. Zad. 22. Napisz program rzeczywista, który liczbę a podaną jako argument wypisuje w postaci p · 2w Skorzystaj z operacji na bitach i funkcji frexp, ldexp. % ./rzeczywista 2005 0.9790039062500000*2^11

Nie uwzględniaj szczególnej reprezentacji wartości 0. Zad. 23. Mając daną zmienną typu rzeczywistego double i wiedząc, że jest postaci p · 2w oraz posługując się operacjami bitowymi i funkcjami frexp, ldexp skonstruuj liczbę w

p · 2b 2 c Nie uwzgędniaj szczególnej reprezentacji wartości 0. Zad. 24. Napisz program pierwiastek, który oblicza pierwiastek kwadratowy zadanej liczby. Nie korzystaj z istniejącej funkcji sqrt lecz zaimplementuj wzór Newtona, dla którego √ x = lim an , n→∞

gdzie (an ) jest ciągiem zadanym rekurencyjnie an+1 = 12 (an + axn ). Wykonaj 10 iteracji przez kopiowanie fragmentu programu. Zwróć uwagę, na a) szybkość zbiegania w zależności od początkowej wartości a0 , b) zachowanie dla ujemnych x. Dla ustalenia wartości a0 skorzystaj z poprzedniego zadania. Zad. 25. Korzystając ze wzoru Gaussa napisz program dzien, który oblicza dzień tygodnia na podstawie daty. Numer dnia określony jest następującym wzorem r/4 − r/100 + r/400 + 367m/12 + d + 365r , 5

gdzie d ∈ {1, . . . } jest dniem miesiąca, m ∈ {1, . . . , 12} – miesiącem, r – rokiem. Dzielenie jest typu całkowitego. Ponadto za początek roku należy przyjąć dzień 1 marca. Zad. 26. Napisz program podatki obliczający wysokość podatku dochodowego w 2003 roku. Przyjmij następujące dane: skala 19 % dla dochodów poniżej 37024 zł, 30 % dla dochodów poniżej 74048 zł, 40 % dla dochodów poniżej 600000 zł, 50 % dla pozostałych. Kwota wolna od podatku to 530.08 zł. Dane dotyczące wysokości kwot i podatku odpowiadające poszczególnym progom zapisz w tablicy. Zad. 27. Napisz program dziennik, który oblicza ile dni upłynęło od podanej daty do dnia uruchomienia programu. Skorzystaj z doświadczeń programu dzien i funkcji time przekazującej liczbę sekund jakie upłynęły od godziny 000 dnia 1 stycznia 1970 roku. W zależności od wprowadzonych danych wynikiem działania programu powinno być wypisanie jednego sposród poniższych komunikatów: a) Dziś masz mały jubileusz! b) Jutro masz mały jubileusz! c) Pojutrze masz mały jubileusz! d) Do najbliższej 1000-nicy zostało Ci n dni. e) Czy na pewno się już urodziłeś? Zad. 28. Korzystając z liczb całkowitych typu int napisz program silnia obliczający silnię zadanej liczby oraz liczbę wystąpień cyfry 7 w jej zapisie dziesiętnym. Silnie jakiej największej liczby możemy policzyć tym programem? Zad. 29. Napisz program podzielne znajdujący wszystkie liczby z zakresu od 1 do 1000, które są podzielne przez sumę swoich cyfr. Zad. 30. Napisz program podzielne2 znajdujący wszystkie liczby z zakresu od 1 do 1000, które są jednocześnie podzielne przez sumy swoich parzystych i nieparzystych cyfr. Zad. 31. Napisz program cezar, który czyta bajty ze standardowego strumienia wejściowego (funkcja cin.get) i przepisuje do standardowego strumienia wyjściowego (cout.put) zastępując litery alfabetu łacińskiego literami znajdującymi się w alfabecie o n pozycji dalej. Wartość n odczytaj z parametru uruchomienia programu. 6

Zad. 32.

Napisz program wielomian obliczający wartość wielomianu

w(x) = 100x3 − 625x2 + 1183.19x − 660.489 = 100(x − 3.19)(x − 2.05)(x − 1.01) w zadanym punkcie. Obliczenie wartości wielomianu różnymi sposobami a) 100 * x * x * x - 625 * x * x + 1183.19 * x - 660.489 b) ( ( 100 * x - 625 ) * x + 1183.19 ) * x - 660.489 c) 100 * ( x - 3.19 ) * ( x - 2.05 ) * ( x - 1.01 ) d) 100 * pow( x, 3 ) - 625 * pow( x, 2 ) + 1183.19 * x - 660.489 zapisz w postaci osobnych funkcji w1, w2, w3. Porównaj wyniki obliczeń zrealizowanych różnymi sposobami. Następnie zapisując na kartce wyniki i traktując program jako programowalny kalkulator, dzięki któremu mamy łatwość liczenia wartości wielomianu w poszczególnych punktach, znajdź metodą bisekcji miejsca zerowe. Zad. 33. Napisz program bisekcja – rozwinięcie programu wielomian – umożliwiający obliczanie miejsc zerowych wielomianu w(x) = 100x3 − 625x2 + 1183.19x − 660.489 metodą bisekcji. Uzyskane wyniki porównaj z dokładnymi wartościami miejsc zerowych wielomianu. Zad. 34. Napisz program styczne będący modyfikacją programu bisekcja, znajdujący metodą stycznych, w której „kandydata” xn na miejsce zerowe funkcji f (x) zastępujemy „kandydatem lepszym” xn+1 = xn −

f (xn ) f 0 (xn )

Zad. 35. Napisz program rekurencja porównujący rekurencyjne i iteracyjne obliczanie a) silni, b) liczb Fibonacciego.

7

Liczby Fibonacciego zadane są rekurencyjnie fn+2 = fn+1 + fn oraz f0 = f1 = 1. Następnie oblicz 10!, 20!, 50!, f10 , f20 , f50 . Skomentuj uzyskane wyniki. Zad. 36. Napisz program euklides znajdujący największy wspólny dzielnik korzystając z algorytmu Euklidesa: znalezienie N W D(a, b), gdzie a > b sprowadza się do (poza przypadkiem kiedy a jest wielokrotnością b) do znalezienia N W D(b, reszta z dzielenia a przez b). Rozwiązanie zapisz na dwa sposoby: iteracyjnie i rekurencyjnie. Zad. 37. Napisz program newton znajdujący dla zadanego punktu x0 miejsce zerowe wielomianu w(x) = (x − 1)(x − 2)(x − 3)(x − 4) przy pomocy metody Newtona (stycznych; polegającej na „zastąpieniu” kandydata i) xi na miejsce zerowe na ogół „lepszym” kandydatem xi+1 = xi − ww(x 0 (x ) ). Oblii czenia wykonaj w dziedzinie zespolonej. Następnie oblicz miejsca zerowe dla następujących wartości początkowych x0 : a) 1.05, 2.1, 2.9, 4.1, b) 2.5, c) 2.4, 2.6. Poniżej przedstawiono działanie przykładowego rozwiązania. % ./newton (0.95,0.1) w((9.4999999999999996e-01,1.0000000000000001e-01)) = (2.0920625000000023e-01,-7.0835000000000004e-01) w((1.0080677933838893e+00,1.8067861263060966e-02)) = (-5.1237462461980618e-02,-1.0518620817044756e-01) w((1.0005141051464106e+00,-5.2136674958264129e-04)) = (-3.0847118896539993e-03,3.1223053063340199e-03) w((1.0000000151267927e+00,9.8408636207405684e-07)) = (-9.0771406412290008e-08,-5.9045178449450769e-06) w((1.0000000000017750e+00,-5.4577759886899162e-14)) = (-1.0650147430589576e-11,3.2746655931926366e-13) %

Tworzenie rysunków przy wykorzystaniu programu gnuplot Zad. 38. Korzystając z doświadczeń programu cezar napisz program litery1 obliczający częstość występowania poszczególnych znaków (spacji i małych liter alfabetu łacińskiego) oraz przygotowujący plik z danymi dla programu gnuplot. Następnie korzystając z tego programu przygotuj wykres słupkowy. Zad. 39. Rozbuduj program litery1 do programu litery2 aby przykładowe obliczenia 8

% ./litery2 pt.txt h.txt

przygotowały dane (pliki pt.txt.dat, h.txt.dat oraz skrypt.gp) dla otrzymania rysunku programem gnuplot: % gnuplot -persist skrypt.gp "pt.txt.dat" "h.txt.dat" 0.2

0.15

0.1

0.05

0 _

a

b

c

d

e

f

g

h

i

j

k

l

m n

o

p

q

r

s

t

u

v

w

x

y

z

Zad. 40. Napisz program kopiuj kopiujący maksymalnie n znaków pomiędzy standardowym strumieniem wejściowym, a standardowym strumieniem wyjściowym. Następnie korzystając z tego programu stwórz pliki pt100.txt, pt1000.txt i pt10000.txt zawierające odpowiednio 100, 1000 i 10000 pierwszych znaków Pana Tadeusza i przy pomocy programu litery2 stwórz wykres porównawczy częstotliwości występowania liter. Program gnuplot (w wersji 4) umożliwia kolorowanie płaszczyzny. Dane w pliku składają się z trójek (x, y, z) gdzie x, y są współrzędnymi punktu zaś wartości z zostanie przyporządkowany kolor. Ciągi trójek (x, y, z) wyznaczają izolinie (w terminologii gnuplotowo–fizycznej scan’y), a ciągi izolinii rysunek. Poszczególne izolinie rozdzielają puste wiersze. Program test przygotowuje dane kolorujące kwadrat o współrzędnych przeciwległych wierzchołków (−50, −50) i (50, 50) kolorem w zależności od odległości od środka układu współrzędnych. // Program przygotowuje dane dla programu gnuplot kolorujące punkty kwadratu // w funkcji odległości od środka układu współrzędnych. //

9

// Paweł Klimczewski, 27 listopada 2005 #include #include using namespace std; int main() { for ( int y = -50; y { for ( int x = -50; { double r = sqrt( cout << x << ’ ’ } cout << endl; } return 0; }

<= 50; ++y ) x <= 50; ++x ) x * x + y * y ); << y << ’ ’ << r << endl;

Dokonując obliczeń i wczytując dane do programu gnuplot % ./test > test.dat % gnuplot G N U P L O T Version 4.0 patchlevel 0 last modified Thu Apr 15 14:44:22 CEST 2004 System: Linux 2.4.26 > set pm3d map > splot "test.dat"

otrzymujemy rysunek

10

"test.dat" 60 80 70 60 50 40 30 20 10 0

40

20

0

-20

-40

-60 -60

-40

-20

0

20

40

60

Zad. 41. Napisz program newton2 przygotowujący dane dla pokolorawania prostokątnego obszaru płaszczyzny w następujący sposób. Dla każdego punktu (x, y) wyznaczonego przez podział siatką N na N oczek staraj się znaleźć (metodą Newtona) miejsce zerowe wielomianu z n = 1 wykonując nie więcej niż maxcnt iteracji. Jeżeli po wykonaniu i-tej iteracji znajdziemy się nie dalej niż  od j-tego miejsca zerowego to przerywamy iteracje i jako wartość z (odpowiadającą kolorowi punktu) przyjmujemy j. Jeżeli po maxcnt iteracjach nie znajdziemy się odpowiednio blisko żadnego z miejsc zerowych jako wartość z przyjmujemy 0. Program powinien pytać o współrzędne obszaru xmin, ymin, xmax, ymax, stopień wielomianu n, maksymalną liczbę iteracji maxcnt i liczbę oczek siatki N . Zad. 42. Napisz program mandelbrot rysujący bodajże najsłynniejszego fraktala jakim jest zbiór Mandelbrota. Punkt P (x, y) płaszczyzny należy do zbioru Mandelbrota jeżeli ciąg (ak ) : ak ∈ Z, a0 = 0, ak+1 = ak 2 + x + iy jest ograniczony. Okazuje się, że jeżeli ∃k, |ak | > 2 to ciąg nie jest ograniczony. W programie obliczenia są skończone, zatem generowany rysunek będzie odpowiednim przybliżeniem. Dla każdego punktu zbadaj nie więcej niż n wyrazów ciągu (ak ). Jeżeli wszystkie wyrazy spełniają warunek |ak | ≤  to przyjmij, że punkt należy do zbioru Mandelbrota i pokoloruj go wartością 0. Pozostałe punkty pokoloruj w zależności od szybkości rozbiegania (najmniejszej liczbie i, dla której |ai | > ). Jako parametry początkowe przyjmij środek kwadratu x = −0.5, y = 0, 11

długość boku a = 3, n = 100,  = 2. Biblioteka STL Zad. 43. Napisz program filtr odczytujący ze standardowego strumienia wejściowego liczby rzeczywiste xi i wypisujący do standardowego strumienia wyjściowego, te które należą do przedziału (¯ x − σ, x¯ + σ). Skorzystaj z klasy vector. sP n x − xi )2 i=1 (¯ σ= n−1 jest średnim odchyleniem standardowym, a x¯ =

x1 + . . . + xn n

jest średnią arytmetyczną. Zad. 44. Napisz program pierwsze obliczający wszystkie liczby pierwsze mniejsze od 1 000 000. Sprawdzenie czy i jest liczbą pierwszą wykonaj przez√obliczanie reszt z dzielenia i przez kolejne liczby całkowite z przedziału h2, b ici. Następnie zmodyfikuj program tak, aby zapamiętywał obliczane liczby pierwsze na liście (klasa list) i √ sprawdzał jedynie reszty z dzielenia i przez liczby pierwsze nie większe od b ic. Porównaj szybkość obliczeń obu wersji. (bxc oznacza największą liczbę całkowitą nie większą od x.) Zad. 45. Napisz program totolotek losujący 6 różnych liczb z 49 i wypisujący je do standardowego strumienia wyjściowego w sposób uporządkowany. Skorzystaj z klasy set. Dla wylosowania liczby skorzystaj z funkcji rand i srand. Ograniczenie zakresu do przedziału 1, . . . , 49 wykonaj przy pomocy reszty z dzielenia. Zad. 46. Wprowadzając słownik (klasa map) dla zapamiętywana już obliczonych wartości wyrazów ciągu Fibonacciego popraw efektywność liczenia n–tego wyrazu tego ciągu metodą rekurencyjną. int fibonacci( int n ) { return n > 1 ? fibonacci( n - 1 ) + fibonacci( n - 2 ) ? 1; }

Zad. 47. Napisz program lustro odczytujący ze standardowego strumienia wejściowego wiersze i wypisujący je w kolejności odwrotnej, a każdy wiersz od końca do początku. Zadbaj o „wyrównanie” do prawego marginesu tak aby dla danych 12

1 23 456

otrzymać następujący wynik 654 32 1

Zad. 48. Napisz program ciagi obliczający liczbę, parami różnych, n– elementowych ciągów znaków w standardowym strumieniu wejściowym. Dokonaj obliczeń dla tekstów Pana Tadeusza i Hamleta. Zad. 49. Napisz program najczestsze odczytujący ze standardowego strumienia wejściowego słowa i wypisujący pierwszą dziesiątkę najczęściej powtarzających się słów wraz z odpowiadającymi liczbami powtórzeń. Dokonaj obliczeń dla tekstów Pana Tadeusza i Hamleta. Zad. 50. Poszczególnym literom alfabetu łacińskiego przyporządkowujemy liczby w następujący sposób: a 7→ 17, . . . , j 7→ 26, k 7→ 1, l 7→ 2, . . . , z 7→ 16. Każdemu słowu przyporządkowujemy liczbę równą iloczynowi liczb odpowiadających literom. Napisz program milion odczytujący słowa (składające się wyłącznie z małych liter alfabetu łacińskiego) i znajdujący te o wartościach najbliższych 1000000. Dokonaj obliczeń dla tekstów Pana Tadeusza i Hamleta. Zad. 51. Na półce ustawiono obok siebie w sposób losowy 4 zielone, 5 czerwonych i 8 niebieskich książek. Oblicz prawdopodobieństwo zdarzenia, że losowo wybrana książka posiada z każdej strony po n bezpośrednich sąsiadów tego samego koloru. Kolory książek sąsiadujących ze strony lewej mogą być różne od książek ze strony prawej. Przykładowo zaznaczona nawiasami kwadratowymi książka n c z z n [ c ] c c c z c c n z

posiada bezpośrednio ze strony lewej jednego sąsiada w kolorze niebieskim, a ze strony prawej trzech sąsiadów w kolorze czerwonym. Skorzystaj z funkcji next_permutation i prev_permutation. Zad. 52. Napisz program kalkulator będący kalkulatorem liczącym w Odwrotnej Notacji Polskiej. Program powinien czytać dane ze standardowego strumienia wejściowego. Jeżeli wprowadzona dana jest liczbą program dopisuje ją na wierzchołku stosu. Jeżeli jest jednym z symboli działań arytmetycznych (+,-,*,/) program odczytuje i usuwa z wierzchołka stosu dwie liczby, które traktuje jak argumenty działania, oblicza wynik działania i umieszcza 13

na wierzchołku stosu. Po każdej operacji wypisuje na ekranie wartość elementu z wierzchołka stosu. Skorzystaj z klasy stack. Zad. 53. Napisz program odleglosci odczytujący ze standardowego strumienia wejściowego liczby zespolone zi i przepisujący je do plików: a) do pliku z1.txt uporządkowane względem odległości od początku układu współrzędnych (najpierw liczby bliższe potem dalsze), b) do pliku z2.txt uporządkowane względem odległości od prostej y = x (najpierw liczby dalsze potem bliższe). Zad. 54. Napisz program poeta dopisujący kontynuację zadanego tekstu. Program uruchomiony w sposób % ./poeta n < pt.txt

powinien odczytać ze standardowego strumienia wejściowego wszystkie k znaków zi obliczając statystykę Sn (k) częstości wystąpień n–elementowych podciągów znaków. Następnie program powinien obliczyć taki znak zk+1 , dla którego odległość d(Sn (k), Sn (k + 1)) będzie najmniejsza. I kolejno obliczać dalsze znaki zk+2 , zk+3 itd. Statystyka Sn jest n! składnikowym wektorem. Odległość d jest zwykłą odległością kartezjańską w przestrzeni n! wymiarowej unormowanych wektorów Sn . (Jako miarę identyczności statystyk można także przyjąć euklidesowy iloczyn skalarny hSn (k), Sn (k + 1)i unormowanych wektorów Sn .)

14

Rozwiązania zadań Zad. 1. % g++ -o hello hello.cc % ./hello Programowanie w C++ jest proste i przyjemne! %

Zad. 2. % g++ -c -o hello.o hello.cc % g++ -o hello hello.o % ./hello Programowanie w C++ jest proste i przyjemne! %

Zad. 3. % g++ -c -o main.o main.cc % gcc -c -o fun.o fun.c % g++ -o main main.o fun.o % ./main Hello world %

Zad. 4. all: hello main hello: hello.cc g++ -o hello hello.cc main: main.cc fun.c fun.h g++ -c -o main.o main.cc gcc -c -o fun.o fun.c g++ -o main main.o fun.o .PHONY: clean clean: rm -f *.o hello main

15

Zad. 5. %.o: %.c gcc -c -o $@ $< %.o: %.cc g++ -c -o $@ $< %: %.o g++ -o $@ $^ all: hello main hello: hello.o main: main.o fun.o

Zad. 6. CCFLAGS += -g CXXFLAGS += -g all: hello main hello: hello.o $(CXX) -o $@ $< main: main.o fun.o $(CXX) -o $@ $^

Zad. 7. % g++ -O0 -o pierwsze pierwsze.cc % time pierwsze > /dev/null 7.900u 0.000s 0:07.90 100.0% % g++ -O2 -o pierwsze pierwsze.cc % time pierwsze > /dev/null 7.490u 0.000s 0:07.49 100.0%

0+0k 0+0io 265pf+0w

0+0k 0+0io 268pf+0w

Zad. 10. // Program wypisuje kolejne potęgi liczby pi z zadaną dokładnością // korzystając z biblioteki języka C. // // Paweł Klimczewski, 10 października 2005 #include #include

16

int main() { printf("potęga wartość\n" "----------------\n"); printf("1 %5.1f\n",M_PI); printf("2 %6.2f\n",M_PI*M_PI); printf("3 %7.3f\n",M_PI*M_PI*M_PI); printf("4 %8.4f\n",M_PI*M_PI*M_PI*M_PI); printf("5 %9.5f\n",M_PI*M_PI*M_PI*M_PI*M_PI); return 0; } // Program wypisuje kolejne potęgi liczby pi z zadaną dokładnością // korzystając z biblioteki języka C++. // // Paweł Klimczewski, 10 października 2005 #include #include #include using namespace std; int main() { cout<<"potęga wartość"<<endl; cout<<"-----------------"<<endl<
Zad. 11. // Program odczytuje dwie liczby i wypisuje ich iloraz i sumę. // Wersja w stylu C++. // // Paweł Klimczewski, 10 października 2005 #include using namespace std; int main() { cout<<"Podaj pierwszą liczbę"<<endl;

17

int i; cin>>i; cout<<"Podaj drugą liczbę"<<endl; int j; cin>>j; cout<<"Pierwsza odczytana liczba "<<<endl; cout<<"Druga odczytana liczba "<<j<<endl; cout<<"Iloraz "< int main() { printf("Podaj pierwszą liczbę\n"); int i; scanf("%d",&i); printf("Podaj drugą liczbę\n"); int j; scanf("%d",&j); printf("Pierwsza odczytana liczba %d\n",i); printf("Druga odczytana liczba %d\n",j); printf("Iloraz %d\n",i/j); printf("Suma %d\n",i+j); return 0; }

Zad. 12. // Program oblicza zadłużenie wobec barku wydziałowego na podstawie rachunku // nadesłanego w pliku;) // // Paweł Klimczewski, 10 października 2005 #include int main() { double cena1; scanf("%*[A-Za-z ]:%lf\n",&cena1); double cena2; scanf("%*[A-Za-z ]:%lf\n",&cena2);

18

double cena3; scanf("%*[A-Za-z ]:%lf\n",&cena3); printf("%.2f+%.2f+%.2f=%.2f\n",cena1,cena2,cena3,cena1+cena2+cena3); return 0; }

Zad. 13. // Program zamienia miejscami liczby zapisane w pliku 2pi.txt. // // Paweł Klimczewski, 10 października 2005 #include #include <string> using namespace std; int main() { fstream f("2pi.txt"); string s1, s2; f>>s1>>s2; f.seekp(0,ios::beg); f<<s2<<endl<<s1<<endl; return 0; }

Zad. 14. // Program sprawdza liczbę cyfr znaczących dla zmiennych typu float, double // i long double. // // Paweł Klimczewski, 19 października 2005 #include #include #include using namespace std; int main() { // dla łatwiejszego porównania wyników cout << setprecision( 40 ); // float cout << "----- float" << endl; float fsuma = 0, poprzednia_fsuma; int i = 0;

19

do { poprzednia_fsuma = fsuma; fsuma = fsuma + pow( 10.f, -i ); i = i + 1; cout << setw( 2 ) << i << ": " << fsuma << endl; } while ( poprzednia_fsuma != fsuma ); // double cout << "----- double" << endl; double dsuma = 0, poprzednia_dsuma; i = 0; do { poprzednia_dsuma = dsuma; dsuma = dsuma + pow( 10., -i ); i = i + 1; cout << setw( 2 ) << i << ": " << dsuma << endl; } while ( poprzednia_dsuma != dsuma ); // long double cout << "----- long double" << endl; long double ldsuma = 0, poprzednia_ldsuma; i = 0; do { poprzednia_ldsuma = ldsuma; ldsuma = ldsuma + pow( 10.l, -i ); i = i + 1; cout << setw( 2 ) << i << ": " << ldsuma << endl; } while ( poprzednia_ldsuma != ldsuma ); return 0; }

Zad. 15. // Program oblicza sumę odwrotności kwadratów z zakresu 1...10^8 posługując // się zmiennymi typu float, double i long double. // // Paweł Klimczewski, 19 października 2005 #include #include #include

20

using namespace std; int main() { cout << setprecision( 40 ); // dla łatwiejszego porównania wyników // float, od 1 w górę float fsuma = 0; for ( int i = 1; i <= 100000000; ++i ) { float f = i; fsuma = fsuma + 1.f / f / f; } cout << fsuma << endl; // float, od 10^8 w dół fsuma = 0; for ( int i = 100000000; i >= 1; --i ) { float f = i; fsuma = fsuma + 1.f / f / f; } cout << fsuma << endl; // double, od 1 w górę double dsuma = 0; for ( int i = 1; i <= 100000000; ++i ) { double d = i; dsuma = dsuma + 1. / d / d; } cout << dsuma << endl; // double, od 10^8 w dół dsuma = 0; for ( int i = 100000000; i >= 1; --i ) { double d = i; dsuma = dsuma + 1. / d / d; } cout << dsuma << endl; // long double, od 1 w górę long double ldsuma = 0; for ( int i = 1; i <= 100000000; ++i ) { long double ld = i; ldsuma = ldsuma + 1.l / ld / ld; }

21

cout << ldsuma << endl; // long double, od 10^8 w dół ldsuma = 0; for ( int i = 100000000; i >= 1; --i ) { long double ld = i; ldsuma = ldsuma + 1.l / ld / ld; } cout << ldsuma << endl; // suma szeregu nieskończonego cout << M_PI * M_PI / 6 << endl; return 0; }

Zad. 16. // Program zamienia kolejność znaków w pliku. // // Paweł Klimczewski, 4 listopada 2005 #include #include #include <string> using namespace std; int main() { cout << "Podaj nazwę pliku" << endl; string nazwa; cin >> nazwa; fstream f( nazwa.c_str() ); f.seekg( 0, ios::end ); int n = f.tellg(); for ( int i = 0; i < n / 2; ++i ) { f.seekg( i, ios::beg ); char c1 = f.get(); f.seekg( -( i + 1 ), ios::end ); char c2 = f.get(); f.seekp( i, ios::beg ); f.put( c2 ); f.seekp( -( i + 1 ), ios::end ); f.put( c1 ); } return 0; }

22

Zad. 17. // Program wypisuje w kolejnych wierszach coraz dokładniejszą wartość // liczby pi. // // Paweł Klimczewski, 4 listopada 2005 #include #include #include using namespace std; int main() { cout << "Podaj liczbę wierszy" << endl; int i; cin >> i; if ( !cin || i <= 0 || i > 9 ) { cout << "Nierozsądna odpowiedź" << endl; } else { for ( int j = 0; j < i; ++j ) { cout << setprecision( 1 + j ) << fixed << M_PI << endl; } } return 0; }

Zad. 18. // Program wypisuje w kolejnych wierszach coraz dokładniejszą wartość // kolejnej potęgi liczby pi. // // Paweł Klimczewski, 4 listopada 2005 #include #include #include using namespace std; int main() { cout << "Podaj liczbę wierszy" << endl; int i;

23

cin >> i; if ( !cin || i <= 0 || i > 9 ) { cout << "Nierozsądna odpowiedź" << endl; } else { cout << "potęga wartość" << endl << "-------------------------" << endl; for ( int j = 0; j < i; ++j ) { double potega = pow( M_PI, j + 1 ); int cyfr = int( log10( potega ) ); cout << setw( 10 - cyfr ) << left << j + 1 << setprecision( j + 1 ) << fixed << potega << endl; } } return 0; }

Zad. 19. // Program rysuje kwadrat z przekątną. // // Paweł Klimczewski, 4 listopada 2005 #include using namespace std; int main() { cout << "Podaj rozmiar int n; cin >> n; if ( !cin || n <= 0 || { cout << "Niepoprawne } else { for ( int y = 0; y < { for ( int x = 0; x { char znak = ’ ’; if ( !x || !y || {

kwadratu" << endl;

n > 20 ) dane!" << endl;

n; ++y ) < n; ++x )

x == n - 1 || y == n - 1 || x == y )

24

znak = ’*’; } cout << znak; } cout << endl; } } return 0; } // Program rysuje tabelkę. // // Paweł Klimczewski, 4 listopada 2005 #include #include using namespace std; int main() { const int n = 4; for ( int y = 0; y < n; ++y ) { cout << "---------------------" << endl; for ( int x = 0; x < n; ++x ) { cout << "| " << setw(2) << ( x + 1 ) * ( y + 1 ) << " "; } cout << "|" << endl; } cout << "---------------------" << endl; return 0; }

Zad. 20. // Program oblicza liczbę odczytanych słów i średnią długość słowa // // Paweł Klimczewski, 4 listopada 2005 #include #include <string> using namespace std; int main() { int n = 0, znakow = 0;

25

string s; while ( cin >> s ) { ++n; znakow += s.size(); } cout << "Liczba słów: " << n << endl << "Średnia długość słowa: " << 1. * znakow / n << endl; return 0; }

Zad. 21. // Program stara się naśladować systemowe polecenie wc. // // Paweł Klimczewski, 4 listopada 2005 #include #include <sstream> #include <string> using namespace std; int main() { int wierszy = 0, slow = 0, znakow = 0; string s; while ( getline( cin, s ) ) { ++wierszy; istringstream is( s ); while ( is >> s ) { ++slow; znakow += s.size(); } } cout << "Wierszy " << wierszy << ", słów " << slow << ", znaków " << znakow << endl; return 0; }

Zad. 22. // Program wypisuje wartość podanej liczby w postaci c*2^m. // // Paweł Klimczewski, 11 listopada 2005

26

#include #include #include #include

<sstream>

using namespace std; // Odczytanie wartości na podstawie napisu p wraz ze sprawdzeniem // zapisuję w osobnej funkcji. template void czytaj_z_napisu( T& x, const char* p ) { if ( !p ) { cerr << "Należy podać liczbę!" << endl; exit( 1 ); } istringstream is( p ); is >> x; if ( !is ) { cerr << "To nie jest liczba!" << endl; exit( 1 ); } int i = is.tellg(); is.seekg( 0, ios::end ); int j = is.tellg(); if ( i != j ) { // np. 1x lub 1.2.3 itd. cerr << "W danej jest coś więcej niż liczba!" << endl; exit( 1 ); } } int main( int argc, char* argv[] ) { double x; czytaj_z_napisu( x, argc < 2 ? NULL : argv[ 1 ] ); int m; double c = frexp( x, &m ); cout << fixed << setprecision( 16 ) << c << "*2^" << m << endl; return 0; }

Zad. 23. // Program odczytuje podaną wartość x=c*2^m, a następnie konstruuje liczbę // c*2^(m/2).

27

// // Paweł Klimczewski, 11 listopada 2005 #include #include #include #include

"czytaj.h"

using namespace std; int main( int argc, char* argv[] ) { // Dla odczytania wartości podanej przez użytkownika korzystam // z funkcji czytaj_double z programu rzeczywista. double x; czytaj_z_napisu( x, argc < 2 ? NULL : argv[ 1 ] ); int m; double c = frexp( x, &m ); m >>= 1; x = ldexp( c, m ); cout << fixed << setprecision( 16 ) << x << endl; return 0; }

Zad. 24. // Program oblicza pierwiastek zadanej liczby metodą Newtona. // // Paweł Klimczewski, 11 listopada 2005 #include #include #include #include

"czytaj.h"

using namespace std; int main( int argc, char* argv[] ) { // Odczytuję liczbę pierwiastkowaną x. Korzystam z funkcji // czytaj_z_napisu z programu rzeczywista. double x ; czytaj_z_napisu( x, argc < 2 ? NULL : argv[ 1 ] ); // Obliczam początkowe przybliżenie pierwiastka. int m; double c = frexp( x, &m ); m >>= 1; double p = ldexp( c, m ); cout << "Kandydat na wartość pierwiastka = " << p << endl;

28

cout << "Kolejne iteracje" << endl; cout << left << scientific << setprecision( 16 ); // Iteracyjnie znajduję piewiastek. for ( int i = 1; ; ++i ) { double q = 1. / 2 * ( p + x / p ); if ( p == q ) { // Iteracja nie przyniosła zmian. Przerywam pętlę. break; } cout << setw( 6 ) << i << q << endl; p = q; } return 0; }

Zad. 25. // Program oblicza dzień tygodnia. // // Paweł Klimczewski, 11 listopada 2005 #include #include #include #include

<sstream>

using namespace std; // Zadaniem funkcji jest odczytanie ze strumienia cin liczby // i odpowiednie reagowanie na ewentualne błędy. System operacyjny przesyła // do programu całe wprowadzone wiersze w momencie naciśnięcia klawisza Enter. template void czytaj_z_wejscia( T& x, const char* p = "Podaj liczbę" ) { while ( true ) { cout << p << endl; string s; getline( cin, s ); if ( !cin ) { if ( cin.eof() ) { cerr << "Koniec danych?! Kończę pracę programu!" << endl; exit( 1 ); } cerr << "Błąd przy czytaniu wiersza!" << endl;

29

cin.clear(); continue; } istringstream is( s ); is >> x; if ( !is ) { cerr << "To nie była liczba!" << endl; continue; } is >> ws; int j = is.tellg(); if ( j != -1 && j != s.size() ) { cerr << "To nie była tylko liczba!" << endl; continue; } break; } } int main() { int r; czytaj_z_wejscia( int m; czytaj_z_wejscia( int d; czytaj_z_wejscia( if ( m < 3 ) { m += 10; r -= 1; } else { m -= 2; } int n = r / 4 - r

r, "Podaj rok" ); m, "Podaj miesiąc" ); d, "Podaj dzień" );

/ 100 + r / 400 + 367 * m / 12 + d + r * 365;

const char* dni_tygodnia[]= { "niedziela", "poniedziałek", "wtorek", "środa", "czwartek", "piątek", "sobota" }; cout << "To jest " << dni_tygodnia[ n % 7 ] << "." << endl; return 0; }

30

Zad. 26. // Program oblicza wielkość podatku na podstawie podanego dochodu. zgodnie // ze skalą z 2005 roku. // // Paweł Klimczewski, 13 listopada 2005 #include #include "czytaj.h" using namespace std; int main( int argc, char* argv[] ) { double podstawa; czytaj_z_napisu( podstawa, argc < 2 ? NULL : argv[ 1 ] ); double progi[] = { 600000 , 50, 74048 , 40, 37024 , 30, int( 530.08 / 0.19 * 100 + 0.5 ) / 100., 19, 0 }; double podatek = 0; for ( int i = 0; progi[ i ]; i += 2 ) { if ( podstawa > progi[ i ] ) { podatek += ( podstawa - progi[ i ] ) * progi[ i + 1 ] / 100.; podstawa = progi[ i ]; } } cout << "Należny podatek wynosi " << int( podatek + 0.5 ) << " zł" << endl; return 0; }

Zad. 27. // Program oblicza liczbę dni jakie upłynęły od zadanej daty. // // Paweł Klimczewski, 11 listopada 2005 #include #include #include "czytaj.h" using namespace std;

31

int main() { int r; czytaj_z_wejscia( r, int m; czytaj_z_wejscia( m, int d; czytaj_z_wejscia( d, // Konwersja podanej // rok zaczyna się w if ( m > 2 ) { m = m - 2; } else { m = m + 10; r = r - 1; }

"Podaj rok" ); "Podaj miesiąc" ); "Podaj dzień" ); daty do postaci wymaganej we wzorze Gaussa, czyli marcu.

// Obliczamy numer podanego dnia ze wzoru Gaussa. int t = r / 4 - r / 100 + r / 400 + 367 * m / 12 + d + r * 365; // 1 stycznia 1970 odpowiada we wzorze Gaussa dacie 1 listopada 1969. // Obliczamy numer tego dnia. int t0 = 1969 / 4 - 1969 / 100 + 1969 / 400 + 367 * 11 / 12 + 1 + 1969 * 365; // Zatem od 1 stycznia 1970 do podanego dnia upłynelo t - t0 dni. // Z drugiej strony funkcja time podaje liczbę sekund jakie upłynęły // od 1 stycznia 1970 roku od godziny 0.00 do chwili obecnej. // Razem upłynęło: int n = t0 - t + time( NULL ) / 3600 / 24; if ( n > 0 ) { cout << "Żyjesz już " << n << " dni." << endl; if ( n % 1000 == 0 ) { cout << "Dziś masz mały jubileusz!" << endl; } else { long p = 1000 - n % 1000; if ( p == 1 ) { cout << "Jutro masz mały jubileusz!" << endl;

32

} else if ( p == 2 ) { cout << "Pojutrze masz mały jubileusz!" << endl; } else { cout << "Do najblizszej 1000-nicy zostalo Ci " << p << " dni." << endl; } } } else { cout << "Na pewno już się urodziłeś?" << endl; } return 0; }

Zad. 28. // Program oblicza silnię zadanej liczby oraz ilość cyfr 7 w jej zapisie. // // Paweł Klimczewski, 11 listopada 2005 #include #include #include #include

<sstream> "czytaj.h"

using namespace std; int silnia( int n ) { return n > 1 ? n * silnia( n - 1 ) : 1; } int main() { // Dla odczytania wartości podanej przez użytkownika korzystam // z funkcji czytaj_z_wejscia z programu rzeczywista. int x; czytaj_z_wejscia( x ); int s = silnia( x ); ostringstream os; os << s; string t = os.str(); int n = 0; for ( int i = 0; i < t.size(); ++i ) {

33

if ( t[ i ] == ’7’ ) ++n; } cout << x << "!=" << s << endl; cout << "Liczba siódemek w zapisie = " << n << endl; return 0; }

Zad. 29. // Program znajduje wszystkie liczby całkowite z zakresu 1..1000 podzielne // przez sumę swoich cyfr. // // Paweł Klimczewski, 13 listopada 2005 #include #include <sstream> using namespace std; int main() { for ( int i = 1; i <= 1000; ++i ) { ostringstream os; os << i; const string& s = os.str(); int suma = 0; for ( int j = 0; j < s.size(); ++j ) { suma += s[ j ] - ’0’; } if ( i % suma == 0 ) cout << i << " "; } cout << endl; return 0; }

Zad. 30. // Program znajduje wszystkie liczby całkowite z zakresu 1..1000 podzielne // jednocześnie przez sumy swoich parzystych i nieparzystych cyfr. // // Paweł Klimczewski, 13 listopada 2005 #include #include <sstream> using namespace std;

34

int main() { for ( int i = 1; i <= 1000; ++i ) { ostringstream os; os << i; const string& s = os.str(); int suma_p = 0, suma_n = 0; for ( int j = 0; j < s.size(); ++j ) { int c = s[ j ] - ’0’; ( c % 2 ? suma_n : suma_p ) += c; } if ( suma_p && i % suma_p == 0 && suma_n && i % suma_n == 0 ) cout << i << " "; } cout << endl; return 0; }

Zad. 31. // Program szyfruje dane stosując szyfr cezara. // // Paweł Klimczewski, 13 listopada 2005 #include #include "czytaj.h" using namespace std; int main( int argc, char* argv[] ) { int n; czytaj_z_napisu( n, argc < 2 ? NULL : argv[ 1 ] ); if ( n < 0 || n >= 26 ) { cerr << "Wartość parametru powinna należeć do zakresu 0..25!" << endl; return 1; } while ( true ) { int znak = cin.get(); if ( znak < 0 ) break; // koniec danych if ( znak >= ’a’ && znak <= ’z’ ) znak = ( znak - ’a’ + n ) % 26 + ’a’; else if ( znak >= ’A’ && znak <= ’Z’ ) znak = ( znak - ’A’ + n ) % 26 + ’A’;

35

cout.put( znak ); } return 0; }

Zad. 32. // Program oblicza wartość wielomianu // // w( x ) = 100 x^3 - 625 x^2 + 1183.19 x - 660.489 // // w zadanym punkcie. // // Paweł Klimczewski, 13 listopada 2005 #include #include #include #include

"czytaj.h"

using namespace std; double w1( double x ) { return 100 * x * x * x - 625 * x * x + 1183.19 * x - 660.489; } double w2( double x ) { return ( ( 100 * x - 625 ) * x + 1183.19 ) * x - 660.489; } double w3( double x ) { return 100 * pow( x, 3 ) - 625 * pow( x, 2 ) + 1183.19 * x - 660.489; } int main( int argc, char* argv[] ) { double x; czytaj_z_napisu( x, argc < 2 ? NULL : argv[ 1 ] ); cout << scientific << setprecision( 16 ) << "w(" << x << ")=" << endl << w1( x ) << endl << w2( x ) << endl << w3( x ) << endl; return 0; }

36

Zad. 33. // Program oblicza miejsca zerowe wielomianu // // w( x ) = 100 x^3 - 625 x^2 + 1183.19 x - 660.489 // // metodą bisekcji. // // Paweł Klimczewski, 13 listopada 2005 #include #include #include #include

"czytaj.h"

using namespace std; double w1( double x ) { return 100 * x * x * x - 625 * x * x + 1183.19 * x - 660.489; } double w2( double x ) { return ( ( 100 * x - 625 ) * x + 1183.19 ) * x - 660.489; } double w3( double x ) { return 100 * ( x - 3.19 ) * ( x - 2.05 ) * ( x - 1.01 ); } double w4( double x ) { return 100 * pow( x, 3 ) - 625 * pow( x, 2 ) + 1183.19 * x - 660.489; } // Aby porównać miejsca zerowe znalezione dla różnych funkcji obliczających // wartość wielomianu w punkcie, metodę bisekcji zapisuję w osobnej funkcji. void bisekcja( double x1, double x2, double (*w)(double) ) { double y1 = w( x1 ), y2 = w( x2 ); if ( y1 * y2 == 0 ) { cout << "Masz szczęście - podałeś miejsce zerowe!" << endl; return; } if ( y1 * y2 > 0 ) { cout << "W obu punktach w(x) ma ten sam znak!. Spróbuj ponownie." << endl;

37

return; } if ( x1 > x2 ) { double tmp = x1; x1 = x2; x2 = tmp; } while ( true ) { double xs = ( x1 + x2 ) / 2, ys = w( xs ); if ( ys == 0 || xs == x1 || xs == x2 ) { cout << "x = " << xs << ", w(x) = " << ys << endl; break; } if ( ys * y1 > 0 ) { x1 = xs; } else { x2 = xs; } } } int main( int argc, char* argv[] ) { double x1; czytaj_z_napisu( x1, argc < 3 ? NULL : argv[ 1 ] ); double x2; czytaj_z_napisu( x2, argc < 3 ? NULL : argv[ 2 ] ); cout << scientific << setprecision( 16 ); bisekcja( x1, x2, w1 ); bisekcja( x1, x2, w2 ); bisekcja( x1, x2, w3 ); bisekcja( x1, x2, w4 ); return 0; }

Zad. 34. // Program oblicza miejsca zerowe wielomianu // // w( x ) = 100 x^3 - 625 x^2 + 1183.19 x - 660.489 // // metodą stycznych. //

38

// Paweł Klimczewski, 13 listopada 2005 #include #include #include #include

"czytaj.h"

using namespace std; double w( double x ) { return 100 * x * x * x - 625 * x * x + 1183.19 * x - 660.489; } double dw( double x ) { return 300 * x * x - 1250 * x + 1183.19; } int main( int argc, char* argv[] ) { double x; czytaj_z_napisu( x, argc < 2 ? NULL : argv[ 1 ] ); cout << scientific << setprecision( 16 ); const double EPSILON = 1e-15; while ( true ) { cout << "w(" << x << ") = " << w( x ) << endl; double lepsze_x = x - w( x ) / dw( x ); if ( abs( x - lepsze_x ) < EPSILON ) break; x = lepsze_x; } return 0; }

Zad. 35. // Program oblicza silnię i wyraz ciągu Fibonacciego iteracyjnie // i rekurencyjnie. // // Paweł Klimczewski, 11 listopada 2005 #include #include #include #include

<sys/time.h> "czytaj.h"

using namespace std;

39

int silnia_r( int n ) { return n > 1 ? n * silnia_r( n - 1 ) : 1; } int silnia_i( int n ) { int iloczyn = 1; for ( ; n > 1; --n ) { iloczyn *= n; } return iloczyn; } int fib_r( int n ) { return n > 1 ? fib_r( n - 1 ) + fib_r( n - 2 ) : 1; } int fib_i( int n ) { int poprzedni = 1, biezacy = 1; for ( ; n >= 2; --n ) { int nastepny = biezacy + poprzedni; poprzedni = biezacy; biezacy = nastepny; } return biezacy; } // Funkcja przekazuje aktualny czas w mikrosekundach. W tym celu korzystam // z funkcji systemowej gettimeofday. unsigned int t() { timeval tv; gettimeofday( &tv, NULL ); return tv.tv_sec * 1000000 + tv.tv_usec; } int main() { // Dla odczytania wartości podanej przez użytkownika korzystam // z funkcji czytaj_z_wejscia z programu rzeczywista. int x; czytaj_z_wejscia( x );

40

cout << "Silnia iteracyjnie" << endl; unsigned int t0 = t(); int i = silnia_i( x ); unsigned int t1 = t(); cout << i << ", " << t1 - t0 << endl; cout << "Silnia rekurencyjnie" << endl; t0 = t(); i = silnia_r( x ); t1 = t(); cout << i << ", " << t1 - t0 << endl; cout << "Wyraz ciągu Fibonacciego iteracyjnie" << endl; t0 = t(); i = fib_i( x ); t1 = t(); cout << i << ", " << t1 - t0 << endl; cout << "Wyraz ciągu Fibonacciego rekurencyjnie" << endl; t0 = t(); i = fib_r( x ); t1 = t(); cout << i << ", " << t1 - t0 << endl; return 0; }

Zad. 36. // Program znajduje największy wspólny dzielnik metodą Euklidesa. // // Paweł Klimczewski, 11 listopada 2005 #include #include "czytaj.h" using namespace std;

// iteracyjnie int nwd1( int a, int b ) { while ( b ) { int r = a % b; a = b; b = r; } return a;

41

} // rekurencyjnie int nwd2( int a, int b ) { if ( b != 0 ) return nwd2( b, a % b ); else return a; } int main() { int a; czytaj_z_wejscia( int b; czytaj_z_wejscia( cout << "NWD( " << a << nwd1( a, b ) << nwd2( a, b ) return 0; }

a, "Podaj pierwszą liczbę" ); b, "Podaj drugą liczbę" ); << ", " << b << " ) = " << " = " << endl;

Zad. 37. // Program oblicza miejsca zerowe wielomianu // // w( x ) = (x-1)(x-2)(x-3)(x-4) // // metodą stycznych. // // Paweł Klimczewski, 13 listopada 2005 #include #include #include #include #include

"czytaj.h"

using namespace std; complex<double> w( complex<double> x ) { return ( x - 1. ) * ( x - 2. ) * ( x - 3. ) * ( x - 4. ); } complex<double> dw( complex<double> x ) {

42

// [ ( // = [ // = 4 return

x x^4 x^3 ( (

1 ) ( x - 2 ) ( x - 3 ) ( x - 4 ) ]’ = - 10 x^3 + 35 x^2 - 50 x + 24 ]’ = - 30 x^2 + 70 x - 50 = ( ( 4 x - 30 ) x + 70 ) x - 50 4. * x - 30. ) * x + 70. ) * x - 50.;

} int main( int argc, char* argv[] ) { complex<double> x; czytaj_z_napisu( x, argc < 2 ? NULL : argv[ 1 ] ); cout << scientific << setprecision( 16 ); const double EPSILON = 1e-15; while ( true ) { cout << "w(" << x << ") = " << w( x ) << endl; complex<double> lepsze_x = x - w( x ) / dw( x ); if ( norm( x - lepsze_x ) < EPSILON ) break; x = lepsze_x; } return 0; }

Zad. 38. // Program oblicza częstotliwość występowania liter w tekście odczytanym // ze standardowego strumienia danych // // Paweł Klimczewski, 25 listopada 2005 #include using namespace std; int main() { int liter = 0; // licznik wszystkich znaków // Wystąpienia poszczególnych znaków zliczam w komórkach tablicy. // Pierwsza komórka (indeks 0) odpowiada spacji, druga literze ’a’,..., // dwudziesta siódma literze ’z’. int tab[ 27 ]; for ( int i = 0; i < 27; ++i ) { tab[ i ] = 0; } // Odczytuję dane ze strumienia while ( true ) { int z = cin.get();

43

if ( z == -1 ) break; // koniec danych w strumieniu if ( z == ’ ’ || ( z >= ’a’ && z <= ’z’ ) ) { tab[ z == ’ ’ ? 0 : z - ’a’ + 1 ]++; liter++; } } // Wyniki zapisuję w na ekranie w formacie "dwukolumnowym" for ( int i = 0; i < 27; ++i ) { cout << i << " " << 1. * tab[ i ] / liter << endl; } return 0; }

Przy pomocy przekierowań strumieni dokonuję obliczeń (np. dla tekstu Pana Tadeusza) % ./litery1 < pt.txt > pt.dat

Następnie przy pomocy programu gnuplot tworzę wykres % gnuplot G N U P L O T Version 4.0 patchlevel 0 last modified Thu Apr 15 14:44:22 CEST 2004 System: Linux 2.4.26 > plot "pt.dat" with boxes

44

0.18 "pt.dat" 0.16

0.14

0.12

0.1

0.08

0.06

0.04

0.02

0 0

5

10

15

20

25

30

Przy pomocy poleceń set xrange, set xtics itd. możemy ustalić zakres zmiennych, opisać osie itd. % gnuplot G N U P L O T Version 4.0 patchlevel 0 last modified Thu Apr 15 14:44:22 CEST 2004 System: Linux 2.4.26 > set xrange [-0.5:26.5] > set style fill solid > set boxwidth 0.8 > set xtics ("_" 0,"a" 1,"b" 2,"c" 3,"d" 4,"e" 5,"f" 6,"g" 7,"h" 8,"i" 9, "j" 10,"k" 11,"l" 12,"m" 13,"n" 14,"o" 15,"p" 16,"q" 17,"r" 18,"s" 19,"t" 20, "u" 21,"v" 22,"w" 23,"x" 24,"y" 25,"z" 26) > plot "pt.dat" with boxes

45

0.18 "pt.dat" 0.16

0.14

0.12

0.1

0.08

0.06

0.04

0.02

0 _

a

b

c

d

e

f

g

h

i

j

k

l

m n

o

p

q

r

s

t

u

v

w

x

y

z

Zad. 39. // Program oblicza częstotliwość występowania liter w tekście // i przygotowuje pliki z danymi oraz poleceniami dla programu gnuplot. // // Paweł Klimczewski, 26 listopada 2005 #include #include using namespace std; int n; // liczba wszystkich wykresów double mx=0; // największa z obliczonych częstości // Policzenie znaków zapisuję w postaci osobnej funkcji. int policz( const string& nazwa_pliku, int numer_pliku ) { int liter = 0; // licznik wszystkich znaków int tab[ 27 ]; // licznik poszczególnych znaków for ( int i = 0; i < 27; ++i ) { tab[ i ] = 0; } ifstream is( nazwa_pliku.c_str() ); // Czytam znaki z pliku. while ( true ) {

46

int z = is.get(); if ( z == -1 ) break; // koniec danych if ( z == ’ ’ || ( z >= ’a’ && z <= ’z’ ) ) { tab[ z == ’ ’ ? 0 : z - ’a’ + 1 ]++; liter++; } } // Tworzę plik z danymi dla programu gnuplot. ofstream os( ( nazwa_pliku + ".dat" ).c_str() ); for ( int i = 0; i < 27; ++i ) { double x = i + 0.05 + 0.9 / n * ( numer_pliku + 0.5 ); double y = 1. * tab[ i ] / liter; if ( y > mx ) mx = y; os << x << " " << y << endl; } }

int main( int argc, char* argv[] ) { n = argc - 1; if ( n < 1 ) { cerr << "Podaj nazwy plików z danymi!" << endl; return 0; } for ( int i = 1; i < argc; ++i ) { policz( argv[ i ], i - 1 ); } ofstream skrypt( "skrypt.gp" ); skrypt << "set term aqua" << endl << "set xrange [0:27]" << endl << "set yrange [0:" << 1.2 * mx << "]" << endl << "set style fill solid" << endl << "set boxwidth " << 0.9/n << endl << "set xtics ("; for ( int i = 0; i < 27; ++i ) { if ( i > 0 ) skrypt << ","; skrypt << "\"" << ( i == 0 ? ’_’ : char( ’a’ + i - 1 ) ) << "\" " << i; } skrypt << ")" << endl;

47

skrypt << "plot "; for ( int i = 1; i < argc; ++i ) { if ( i > 1 ) skrypt << ", "; skrypt << "\"" << argv[ i ] << ".dat\" with boxes"; } skrypt << endl; return 0; }

Zad. 40. // Program kopiuje maksymalnie zadanąliczbę znaków. // // Paweł Klimczewski, 26 listopada 2005 #include #include <sstream> using namespace std; int main( int argc, char* argv[] ) { // Sprawdzam czy użytkownik podał argument. if ( argc < 2 ) { cerr << "Należy podać liczbę!" << endl; return 1; } // Jeżeli tak to odczytuję liczbę całkowitą. istringstream is( argv[ 1 ] ); int n; is >> n; if ( !is ) { cerr << "Błąd przy odczytaniu liczby!" << endl; return 1; } // Kopiuję maksymalnie n znaków. for ( ; n > 0; --n ) { int z = cin.get(); if ( z == -1 ) break; // koniec danych cout.put( z ); } return 0; }

48

Zad. 41. // Program przygotowuje dane dla programu gnuplot dla rysunku dorzeczy // pierwiastków równania z^n=1. // // Paweł Klimczewski, 26 listopada 2005 #include #include #include #include

<sstream>

using namespace std; int n; int maxcnt;

// // // double eps = 1e-3; //

stopień wielomianu: z^n - 1 maksymalna liczba iteracji dla pojedynczego punktu satysfakcjonująca odległość od miesca zerowego

int newton( double x, double y ) { complex<double> p( x, y ); for ( int i = 0; i < maxcnt; ++i ) { for ( int j = 0; j < n; ++j ) { if ( norm( p - polar( 1., 2 * j * M_PI / n ) ) < eps ) { return j + 1; } } complex<double> u( 1, 0 ); for ( int j = 1; j < n; ++j ) u *= p; p -= ( p * u - 1. ) / ( 1. * n * u ); } return 0; } int main() { cerr << "Podaj n "; cin >> n; cerr << "Podaj maxcnt "; cin >> maxcnt; cerr << "Podaj obszar x_min y_min x_max y_max "; double x_min, y_min, x_max, y_max; cin >> x_min >> y_min >> x_max >> y_max;

49

cerr << "Podaj rozmiar siatki "; int N; cin >> N; for ( int x = 0; x < N; ++x ) { for ( int y = 0; y < N; ++y ) { double px = x_min + ( double( x - N ) / N + 1 ) * ( x_max - x_min ); double py = y_min + ( double( y - N ) / N + 1 ) * ( y_max - y_min ); cout << px << ’ ’ << py << ’ ’ << newton( px, py ) << endl; } cout << endl; } return 0; } % ./newton > newton.dat Podaj n 5 Podaj maxcnt 100 Podaj obszar x_min y_min x_max y_max -1 -1 1 1 Podaj rozmiar siatki 600 % gnuplot G N U P L O T Version 4.0 patchlevel 0 last modified Thu Apr 15 14:44:22 CEST 2004 System: Linux 2.4.26 > set pm3d map > splot "newton.dat"

50

"newton.dat" 1 0.8

5

0.6

4

0.4

3

0.2

2

0

1

-0.2

0

-0.4 -0.6 -0.8 -1 -1

-0.8

-0.6

-0.4

-0.2

0

0.2

0.4

0.6

0.8

1

Zad. 42. // Program rysuje zbiór Mandelbrota. // // Paweł Klimczewski, 27 listopada 2005. #include #include #include #include

<sstream>

using namespace std; const int n=100; // maksymalna liczba iteracji dla pojedynczego punktu const double eps = 2; int zbadaj_punkt( double x, double y, int n, double eps) { double eps2 = eps * eps; complex< double > z( 0, 0 ); for ( int i = 0; i < n; ++i ) { // z = z^2 + x + i * y; z = z * z + complex< double >( x, y ); // if ( |z| > eps ) if ( norm(z) > eps2 ) {

51

// Ciąg jest rozbieżny. Kolor punktu będzie odpowiadał szybkości // rozbiegania. return 1 + i; } } return 0; } int main() { cerr << "Podaj obszar x_min y_min x_max y_max "; double x_min, y_min, x_max, y_max; cin >> x_min >> y_min >> x_max >> y_max; cerr << "Podaj rozmiar siatki "; int N; cin >> N; for ( int x = 0; x < N; ++x ) { for ( int y = 0; y < N; ++y ) { double px = x_min + ( double( x - N ) / N + 1 ) * ( x_max - x_min ); double py = y_min + ( double( y - N ) / N + 1 ) * ( y_max - y_min ); cout << px << ’ ’ << py << ’ ’ << zbadaj_punkt( px, py, n, eps ) << endl; } cout << endl; } return 0; }

52

"mandelbrot.dat" 1.5 100 1 80 60

0.5

40 0

20 0

-0.5

-1

-1.5 -2

-1.5

-1

-0.5

0

0.5

1

Zad. 43. #include #include #include #include #include



using namespace std; int main() { // Liczby będę pamiętał w wektorze. vector< double > v; // Odczytuję liczby. copy( istream_iterator< double >( cin ), istream_iterator< double >(), back_insert_iterator< vector< double > >( v ) ); // Obliczam średnią. double srednia = accumulate( v.begin(), v.end(), 0. ) / v.size(); // Obliczam średnie odchylenie standardowe. // Korzystam z iteratorów do odczytania elementów wektora. vector< double >::const_iterator it; double sigma = 0; for ( it = v.begin(); it != v.end(); ++it ) { sigma += pow( *it - srednia, 2 );

53

} sigma = sqrt( sigma / ( v.size() - 1 ) ); // Wypisuję wyniki. // Korzystam z indeksów do odczytania elementów wektora. for ( int idx = 0; idx < v.size(); ++idx ) { if ( srednia - sigma < v[ idx ] && v[ idx ] < srednia + sigma ) { cout << v[ idx ] << endl; } } return 0; }

Zad. 44. #include #include <list> #include using namespace std; // Znalezione liczby pierwszę będę zapisywał na liście. list< int > primes; // Funkcja oblicza czy liczba i jest pierwsza. void is_prime( int i ) { int p = int( sqrt( i ) ); list< int >::const_iterator it; for ( it = primes.begin(); it != primes.end() && *it <= p; ++it ) { if ( i % *it == 0 ) return; } primes.push_back( i ); cout << i << " "; } int main() { for ( int i = 2; i < 1000000; ++i ) { is_prime( i ); } return 0; }

54

Zad. 45. #include #include #include #include

<set>

using namespace std; int main() { // Na podstawie aktualnego wskazania zegara inicjuję parametr związany // z generowaniem liczb pseudolosowych. srand( time( 0 ) ); // Wylosowane liczby będę pamiętał w zbiorze. set< int > s; // Losuję. while ( s.size() < 6 ) { s.insert( 1 + rand() % 49 ); } // Wypisuję wyniki. copy( s.begin(), s.end(), ostream_iterator< int >( cout, "\n" ) ); return 0; }

Zad. 46. #include #include <map> using namespace std; // W słowniku f będę pamiętał już obliczone wartości wyrazów ciągu. // Wartości wszystkich wyrazów ciągu są dodatnie. map< int, int > f; int fibonacci( int n ) { // Jeżeli klucz n nie występuje jeszcze w słowniku to wartością f[ n ] // będzie 0. if ( f[ n ] == 0 ) { // Obliczam f[ n ]. f[ n ] = fibonacci( n - 1 ) + fibonacci( n - 2 ); } return f[ n ]; }

55

int main() { f[ 0 ] = f[ 1 ] = 1; cout << "Podaj numer wyrazu ciągu" << endl; int n; cin >> n; cout << "f(" << n << ")=" << fibonacci( n ) << endl; return 0; }

Zad. 47. #include #include #include #include

<string>

using namespace std; // Funkcja porównuje dwa napisy względem ich długości. Skorzystam z niej // dla znalezienia najdłuższego wiersza. bool f( const string& l, const string& r ) { return l.size() < r.size(); } int main() { // Wiersze będę pamiętał w wektorze. vector< string > v; // Czytam kolejne wiersze ze strumienia wejściowego. while ( true ) { string s; getline( cin, s ); if ( !cin ) break; v.push_back( s ); } if ( v.size() > 0 ) { // Znajduje rozmiar najdłuższego wiersza. int mx = max_element( v.begin(), v.end(), f )->size(); // Wyrównuję rozmiar wszystkich wierszy dopisując końcowe spacje // i odwracam kolejność znaków. vector< string >::iterator it; for ( it = v.begin(); it != v.end(); ++it ) { it->resize( mx, ’ ’ ); reverse( it->begin(), it->end() );

56

} // Wypisuję wynik. copy( v.rbegin(), v.rend(), ostream_iterator< string >( cout, "\n" ) ); } return 0; }

Zad. 48. #include #include #include #include

<sstream> <deque> <set>

using namespace std; int main( int argc, char* argv[] ) { if ( argc < 2 ) { cout << "Należy podać długość podciągu!" << endl; return 1; } // Odczytuję parametr n. istringstream is( argv[ 1 ] ); int n; is >> n; if ( !is || n <= 0 ) { cout << "Błędnie podana długość podciągu!" << endl; return 1; } // Obiekt d służy do konstruowania n-elementowego podciągu. deque< char > d; // Podciągi wpisuję do zbioru s. set< deque< char > > s; while ( true ) { // Czytam kolejne znaki. int i = cin.get(); if ( i == -1 ) break; // Koniec danych. char c = i; d.push_back( c ); // Dopisuję kolejny znak do podciągu. if ( d.size() < n ) continue; // Ciąg jest jeszcze za krótki. s.insert( d ); // Dopisuję podciąg do zbioru. d.pop_front(); // Usuwam początkowy znak podciągu. } cout << "liczba różych " << n << "-elementowych podciągów wynosi " << s.size() << endl;

57

return 0; }

Zad. 49. #include #include <map> #include <set> using namespace std; int main() { // W słowniku będę zliczał wystąpienia poszczególnych słów. map< string, int > m; // Odczytuje kolejne słowa i zapisuję w słowniku. while ( true ) { string s; cin >> s; if ( !cin ) break; m[ s ]++; } // Na podstawie zawartości słownika tworzę zbiór, którego elementy są // uporządkowane względem liczby występień słów. set< pair< int, string > > s; map< string, int >::iterator it; for ( it = m.begin(); it != m.end(); ++it ) { s.insert( make_pair( it->second, it->first ) ); } set< pair< int, string > >::const_reverse_iterator jt; // Wypisuję wyniki. int n = 10; for ( jt = s.rbegin(); jt != s.rend() && n; ++jt, --n ) { cout << jt->second << ": " << jt->first << endl; } return 0; }

Zad. 50. #include #include <string> #include <set> using namespace std;

58

// Literze przyporządkowujemy liczbę. int c2i( char c ) { return 1 + ( c - ’a’ + 16 ) % 26; } // Całemu słowu przyporządkowujemy iloczyn liczb odpowiadających literom. int s2i( const string& s ) { int i = 1; for ( string::const_iterator it = s.begin(); it != s.end(); ++it ) i *= c2i( *it ); return i; } int main() { // Słowa zapamiętuję w zbiorze jako pary { wartość bezwzględna różnicy // liczby przyporządkowanej danemu słowu minus 1000000, dane słowo }. // ,,Najlepsze’’ słowa będą znajdowały się na początku. set< pair< int, string > > m; // Odczytuję słowa. while ( true ) { string s; cin>>s; if (!cin) break; m.insert( make_pair( abs( s2i( s ) - 1000000 ), s ) ); } // Wypisuję 10 najlepszych wartości. int n = 10; set< pair< int, string > >::const_iterator it; for ( it = m.begin(); n && it != m.end(); ++it, --n ) { cout << s2i( it->second ) << ": " << it->second << endl; } return 0; }

Zad. 51. #include #include #include #include #include #include #include

<list>

59

using namespace std; // Sprawdzam czy n-ta ksiązka ma taką samą liczbę sąsiadów z każdej strony. bool sprzyjajace( const vector& v, int n ) { // Zliczam sąsiadów po lewej stronie. int l = 0; if ( n > 0 ) { l = 1; for ( int i = n - 2; i >= 0; --i ) { if ( v[ i ] != v[ n - 1 ] ) break; ++l; } } // Zliczam sąsiadów po prawej stronie. int p = 0; if ( n + 1 < v.size() ) { p = 1; for ( int i = n + 2; i < v.size(); ++i ) { if ( v[ i ] != v[ n + 1 ] ) break; ++p; } } return l == p; } int main() { int z = 4; // liczba książek zielonych int c = 5; // czerwonych int n = 8; // niebieskich int a = 0, omega = 0; // liczba zdarzeń sprzyjających i wszystkich. // Poszczególne ustawienia zapamiętuję w wektorze. vector< int > v; for ( int i = 0; i < z; ++i ) v.push_back( 1 ); for ( int i = 0; i < c; ++i ) v.push_back( 2 ); for ( int i = 0; i < n; ++i ) v.push_back( 3 ); // Obliczam pierwszą permutację. while ( prev_permutation( v.begin(), v.end() ) ); next_permutation( v.begin(), v.end() ); // Przeglądam wszystkie permutacje. Jeżeli permutacja jest zdarzeniem // sprzyjającym zwiększam zmienną a. do

60

{ for ( int i = 0; i < v.size(); ++i ) { if ( sprzyjajace( v, i ) ) ++a; ++omega; } } while ( next_permutation( v.begin(), v.end() ) ); // Wypisuję wartość prawdopodobieństwa. cout << a << "/" << omega << endl; return 0; }

Zad. 52. #include #include <sstream> #include <stack> int main() { // Liczby zapamiętuję na stosie. stack< double > stos; // W pętli odczytuje dane wprowadzone przez użytkownika: liczby i symbole // operacji arytmetycznych. while ( true ) { // Wypisuję wartość liczby ze szczytu stosu. if ( !stos.empty() ) { cout << "[" << stos.top() << "]" << endl; } // Odczytuję dane. string s; cin >> s; if ( s != "+" && s != "-" && s != "*" && s != "/" ) { // Skoro nie jest to symbol operacji arytmetycznej to powinna być // to liczba. istringstream is( s ); double d; if ( is >> d ) { stos.push( d ); } else { cout << "Błędne dane!" << endl;

61

} continue; } // Dla każdej operacji potrzebuję dwóch liczb na stosie. if ( stos.size() < 2 ) { cout << "Za mało danych na stosie!" << endl; continue; } // Obliczam wynik działania i zapamiętuję na stosie. if ( s == "+" ) { double suma = stos.top(); stos.pop(); suma += stos.top(); stos.pop(); stos.push( suma ); } else if ( s == "-" ) { double roznica = stos.top(); stos.pop(); roznica -= stos.top(); stos.pop(); stos.push( roznica ); } else if ( s == "*" ) { double iloczyn = stos.top(); stos.pop(); iloczyn *= stos.top(); stos.pop(); stos.push( iloczyn ); } else if ( s == "/" ) { double iloraz = stos.top(); stos.pop(); iloraz = stos.top() / iloraz; stos.pop(); stos.push( iloraz ); } } return 0; }

Zad. 53. #include #include

62

#include #include #include using namespace std; // Funkcje f i g służą do zadania relacji porządkującej wymaganej dla funkcji // sort. bool f( const complex< double >& l, const complex< double >& r ) { return abs( l ) < abs( r ); } bool g( const complex< double >& l, const complex< double >& r ) { // odległość punktu (x1,y1) od prostej y=x wynosi // abs( x1 - y1 ) / sqrt( 2 ) return abs( l.real() - l.imag() ) / sqrt( 2 ) > abs( r.real() - r.imag() ) / sqrt( 2 ); } int main() { // Liczby zapamiętuję w wektorze. vector< complex< double > > v; // Odczytuję je ze strumienia wejściowego. copy( istream_iterator< complex< double > >( cin ), istream_iterator< complex< double > >(), back_insert_iterator< vector< complex< double > > >( v ) ); // Porządkuje względem odległości od początku układu. sort( v.begin(), v.end(), f ); // Zapisuję do pliku z1.txt. fstream f1( "z1.txt" ); copy( v.begin(), v.end(), ostream_iterator< complex< double > >( f1, "\n" ) ); // Porządkuję względem odległości od prostej y=x. sort( v.begin(), v.end(), g ); // Zapisuję do pliku z2.txt. fstream f2( "z2.txt" ); copy( v.begin(), v.end(), ostream_iterator< complex< double > >( f2, "\n" ) ); return 0; }

Zad. 54. #include #include <sstream>

63

#include #include #include #include

<map> <deque> <set>

using namespace std; // Na podstawie argumentu uruchomienia programu odczytuję wartość n. int czytaj_n( int argc, char* argv[] ) { if ( argc < 2 ) { cerr << "Brak parametru n!" << endl; exit( 1 ); } istringstream is( argv[ 1 ] ); int n; is >> n; if ( !is || n <= 0 ) { cerr << "Błędny parametr n!" << endl; exit( 1 ); } return n; } // Elementy słownika możemy traktować jako współrzędne wektora w przestrzeni // 27^n wymiarowej. Funkcja oblicza długość takiego wektora. double d( const map< deque< char >, int >& v ) { double s = 0; map< deque< char >, int >::const_iterator it; for ( it = v.begin(); it != v.end(); ++it ) { s += pow( double( it->second ), 2 ); } return sqrt( s ); } // Dzieląc współrzędne wektora przez jego długość otrzymujemy wektor jednostkowy, // którego koniec leży na jednostkowej sferze. Funkcja oblicza odległość pomiędzy // dwoma punktami sfery odpowiadającymi wektorom u i v. du i dv są odpowiednio // długościami u i v. double odleglosc( const map< deque< char >, int >& u, double du, const map< deque< char >, int >& v, double dv ) { double s = 0; map< deque< char >, int >::const_iterator iu = u.begin(), iv = v.begin();

64

while ( iu != u.end() && iv != v.end() ) { if ( iu->first < iv->first ) { s += pow( iu->second / du, 2 ); ++iu; continue; } if ( iu->first > iv->first ) { s += pow( iv->second / dv, 2 ); ++iv; continue; } s += pow( iu->second / du - iv->second / dv, 2 ); ++iu; ++iv; } for ( ; iu != u.end(); ++iu ) { s += pow( iu->second / du, 2 ); } for ( ; iv != v.end(); ++iv ) { s += pow( iv->second / dv, 2 ); } return sqrt( s ); } // Rozmiar analizowanych podciągów znaków. int n; // Ostatnio odczytany podciąg n znaków. deque< char > p; // Statystyka odpowiadająca tekstowi wzorcowemu. map< deque< char >, int > st0; // Odczytuję tekst wzorcowy i tworzę jego statystykę. void czytaj_dane() { int zn = 0; while ( true ) { int i = cin.get(); if ( i == -1 ) break; // koniec danych ++zn; p.push_back( char( i ) ); if ( p.size() < n ) continue; st0[ p ]++; p.pop_front();

65

} cerr << "Tekst wzorcowy: znaków " << zn << ", ciągów " << n << "-elementowych " << st0.size() << endl << endl; } int main( int argc, char* argv[] ) { n = czytaj_n( argc, argv ); czytaj_dane(); // Długość wektora odpowiadającego statystyce tekstu wzorcowego. double d0 = d( st0 ); // Słownik st1 odpowiada statystyce ,,przedłużanego’’ tekstu. map< deque< char >, int > st1( st0 ); // W pętli obliczam kolejne znaki. while ( true ) { // W zbiorze będę pamiętał pary { odległość pomiędzy statystyką tekstu // wzorcowego a tekstu przedłużonego o dopisany znak, dopisany znak }. // Biorąc pod uwagę uporządkowanie elementów zbioru względem wartości // elementów znak pierwszej pary będzie najlepszym wyborem. set< pair< double, char > > mn; // Obliczam odległości dla dopisania każdej litery i spacji. for ( char idx = ’a’ - 1; idx <= ’z’; ++idx ) { char c = idx < ’a’ ? ’ ’ : idx; p.push_back( c ); st1[ p ]++; double d1 = d( st1 ); mn.insert( make_pair( odleglosc( st0, d0, st1, d1 ), c ) ); st1[ p ]--; p.pop_back(); } char naj = mn.begin()->second; cout << naj << flush; p.push_back( naj ); st1[ p ]++; p.pop_front(); } return 0; }

66

Related Documents

Zadania
October 2019 17
Zadania
April 2020 7
Zadania Testy
October 2019 15
Zadania L4_i6y1s1
November 2019 12
Zadania L3_i6y1s1
November 2019 10