• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Zadanie ze spoj'a: "tabelki liczb" - ocena rozwiązania ---uwaga, kod zadania---

VPS Starter Arubacloud
+1 głos
1,232 wizyt
pytanie zadane 4 kwietnia 2018 w SPOJ przez Jakub 0 Pasjonat (23,120 p.)

Witam, nie chodzi tym razem że coś sędzia nie przepuszcza ;) Chodzi tu bardziej o ocenę algorytmu, ale jednak dałem że pytanie dotyczy serwisu spoj (bo jest tu w końcu rozwiązanie zadania) Na wszelki wypadek też dodałem do kodu kilka błędów by się nie skompilował i nawet jeśli to dawał złe wyniki. Po prostu chciał bym się zapytać o jakość rozwiązania problemu (kodu) tego zadania: http://pl.spoj.com/problems/PP0602B/

Program pisałem prawie 3 godziny ( kilka razy zaczynałem od początku i musiałem mieć przerwy na myślenie i rozrysowanie sobie wszystkiego). Cieszę się jednak że poradziłem sobie z nim samemu. Oto on:

#include <iostream>

//--------------------------------------------------------------------------------------------

template <typename T>
T** createArr(unsigned rows, unsigned col){
    T** arr = new T*[rows];
    for(int i=0; i<rows; i++){
        arr[i] = new T[col];
    }
    return arr;
}

//-------------------------------------------------------------------------------------------

template <typename T>
void deleteArr(T **&arr, unsigned int rows){
    for(int i=0; i<row; i++){
        delete arr[i];
    }delete arr;
}

//----------------------------------------------------------------------------------------------

template <typename T>
void setValues(T** arr, unsigned int rows, unsigned int col){
    for(int i=0; i<rows; i++){
        for(int j=0; j<col; j++){
            std::cin>>arr[i][j];
        }
    }
}

//---------------------------------------------------------------------------------------------

template <typename T>
void showValues(T** arr, unsigned int rows, unsigned int col){
    for(int i=0; i<rows; i++){
        for(int j=0; j<col; j++){
            cout<<arr[i][j]<<" ";
        }
        std::cout<<"\n";
    }
}

//----------------------------------------------------------------------------------------------

template <typename T>
void turnFrame(T** arr, unsigned int rows, unsigned int col){

    int* result = createArr<int>(rows,col);

    for(int i=0; i<rows; i++){
        for(int j=0; j<col; j++){
            result[i][j] = arr[i][j];
        }
    }

    ///-----------------------------------------------------------------------------------------

    result[0][0] = arr[0][1];
    result[rows-1][0] = arr[rows-2][0];
    result[rows-1][col-1] = arr[rows-1][col-2];
    result[0][col-1] = arr[1][col-1];

    for(int i=col-2; i>=1; i--){
        result[0][i] = arr[0][i+1];
    }

    for(int i=1; i<rows-1; i++){
        result[i][0] = arr[i-1][0];
    }

    for(int i=1; i<col-1; i++){
        result[rows-1][i] = arr[rows-1][i-1];
    }

    for(int i=rows-2; i>=1; i--){
        result[i][col-1] = arr[i+1][col-1];
    }

    ///-----------------------------------------------------------------------------------------

    for(int i=0; i<rows; i++){
        for(int j=0; j<=col; j++){
            arr[i][j] = result[i][j];
        }
    }

    deleteArr(result,rows);
}

//---------------------------------------------------------------------------------------------

int main(){
    unsigned int t;
    std::cin>>t;

    for(int i=0; i<t; i++){
        unsigned int l, k;
        std::cin>>l>>k;

        int** arr = createArr<int>(l,k);
        setValues(arr,l,k);
        turnFrame(arr,l,k);
        cout<<"\n";
        showValues(arr,l,k);
        std::cout<<"\n";
        deleteArr(arr,l);
    }

}

//------------------------------------------------------------------------------------------------

Funkcja turnFrame() zawiera właściwy algorytm, inne funkcje odpowiadają za alokacje, zwalnianie pamięci, wypełnianie danymi i rysowanie tablicy 2D. Te funkcje są szablonami bo wcześniej zadanie planowałem rozwiązać inaczej (jeszcze chyba bardziej na około) i potrzebowałem tablicy struktur (a nie chciałem od nowa pisać kodu jej tworzenia). Jak widać kod trochę długawy.

Czy według was stosowanie tablicy tablic jest dobrym pomysłem czy lepiej było użyć jakiś kontenerów? Czy można wykorzystać tu jakiś lepszy algorytm do przesuwania zewnętrznych liczb?

Wiem że umieszczanie tego typu kodu i pytanie się o jego jakość może wydawać się bez sensu ale jakoś zawsze dowiaduje się wtedy nowych przydatnych rzeczy ;)

Dziękuje za rady i serdecznie pozdrawiam.

 

1
komentarz 4 kwietnia 2018 przez monika90 Pasjonat (22,940 p.)
rows kończy się na s, a col nie, dlaczego? turnFrame - lepiej będzie rotateFrame
komentarz 4 kwietnia 2018 przez Jakub 0 Pasjonat (23,120 p.)
Słuszna uwaga, jakoś nie zwróciłem uwagi.
komentarz 4 kwietnia 2018 przez monika90 Pasjonat (22,940 p.)
Tablicy tablic w twoim programie nie ma, masz tablicę wskaźników.
komentarz 4 kwietnia 2018 przez Jakub 0 Pasjonat (23,120 p.)

Czy tablica wskaźników to nie jest coś takiego? :

int* arr[10];

Czyli np 10-elementowa tablica wskaźników. Ja mam przecież dynamiczną tablice 2D :/

czyli np: [3][3] to { {1,2,3}, (...) };

Więc tutaj trzy elementy będące trzy elementowymi blokami pamięci. Więc tablica tablic.

Ale możliwe że stosuje złe nazewnictwo.

*Chociaż racja, każdy element mojej tablicy to wskaźnik na pierwszy element innej tablicy...

To czym jest tablica tablic?

1
komentarz 4 kwietnia 2018 przez monika90 Pasjonat (22,940 p.)
Tablica dwuwymiarowa to jest tablica tablic.

int a[5][6];

Tablica a ma 5 elementów, każdy jej element to tablica 6 intów.
komentarz 4 kwietnia 2018 przez Jakub 0 Pasjonat (23,120 p.)
tzn. to jest tablica 2D tyle że nie dynamiczna?
1
komentarz 4 kwietnia 2018 przez monika90 Pasjonat (22,940 p.)
Tablicę 2D dynamiczną utworzyłbyś tak

new int[zmienna][stała]

problemem jest to, że wszystkie wymiary oprócz pierwszego muszą być stałymi czasu kompilacji.

Dynamiczna tablica wskaźników: new int*[zmienna] to sposób na ominięcie tego problemu.

3 odpowiedzi

0 głosów
odpowiedź 4 kwietnia 2018 przez monika90 Pasjonat (22,940 p.)
wybrane 4 kwietnia 2018 przez Jakub 0
 
Najlepsza

Jestem za tym żeby:

1. Unikać gołego new i delete, a zamiast nich używać std::vector

2. Unikać zbędnych alokacji, czyli alokować tablicę 2d w jednym kawałku, a nie każdy wiersz osobno.

3. Raz jeszcze unikać zbędnych alokacji, rotację można zrobić w miejscu bez tablicy pomocniczej. To pozwala również uniknąć kopiowania.

4. Definiować własne typy danych. Potrzebujesz tablicy dwuwymiarowej? - w twoim programie powinno się pojawić słowo class (może być struct, może być też #include, bo ktoś inny już zdefiniował typ którego potrzebujesz). C++ powstało po to by można było definiować własne typu danych, programowanie w C++ na tym głównie polega.

Przykład

#include <iostream>
#include <vector>

struct array2d
{
    int height, width;
    std::vector<int> data;

    auto& operator () (int row, int col) { return data[row * width + col]; }
    auto& operator () (int row, int col) const { return data[row * width + col]; }

    friend std::ostream& operator << (std::ostream& out, const array2d& a)
    {
        for (int i = 0; i < a.height; ++i)
        {
            for (int j = 0; j < a.width; ++j)
                out << a(i, j) << ' ';

            out << '\n';
        }

        return out;
    }
};

void rotate(array2d& a)
{
    const auto t = a(0, 0);

    for (int i = 0; i < a.width - 1; ++i)
        a(0, i) = a(0, i + 1);

    for (int i = 0; i < a.height - 1; ++i)
        a(i, a.width - 1) = a(i + 1, a.width - 1);
    
    for (int i = a.width - 1; i > 0; --i)
        a(a.height - 1, i) = a(a.height - 1, i - 1);

    for (int i = a.height - 1; i > 1; --i)
        a(i, 0) = a(i - 1, 0);

    a(1, 0) = t;
}

int main()
{
    array2d a{3, 5, {1,2,3,4,5,6,7,8,9,0,1,2,3,4,5}};
    std::cout << a << '\n';
    rotate(a);
    std::cout << a << '\n';
}

Jest to prosty przykład, dlatego dane w klasie array2d są publiczne, to ujdzie w prostym programie na SPOJa, w bardziej złożonych programach ścisła enkapsulacja ma fundamentalne znaczenie.

Przerobienie programu tak by dało się wczytywać tablicę ze standardowego wejścia pozostawiam jako ćwiczenie. smiley

Ćwiczenie dla zaawansowanych - użyć std::rotate

Ćwiczenie dla zaawansowanych numer dwa - użyć std::experimental::ranges::rotate

komentarz 4 kwietnia 2018 przez Jakub 0 Pasjonat (23,120 p.)

Dziękuje za lepszy przykład rozwiązania problemu, jak na razie jeszcze praktycznie nic nie wiem o OOP. Dopiero za tydzień zacznę w książce z której się uczę podstawy obiektowości (tzn. klasy, konstruktory, hermetyzacja) a w następnym już przeciążanie operatorów. Myślę że za miesiąc to tego przykładu powrócę ;)

Ćwiczenie dla zaawansowanych - użyć std::rotate

Ćwiczenie dla zaawansowanych numer dwa - użyć std::experimental::ranges::rotate

Takie cuda to chyba będę za lata dopiero używać :/

komentarz 5 kwietnia 2018 przez Jakub 0 Pasjonat (23,120 p.)
edycja 5 kwietnia 2018 przez Jakub 0
#include <iostream>
#include <vector>

//---------------------------------------------------------------------------------------------------

using container_v = std::vector<int>;

class Array2D{

    container_v arr;
public:

    const int cols;
    const int rows;

    Array2D(int r, int c, container_v a) : rows(r), cols(c), arr(a) {}

    int& element(int row, int col){
        return arr[cols * row + col];
    }

    void show(){
        for(int i=0; i<rows; ++i){
            for(int j=0; j<cols; ++j){
                std::cout<<element(i,j)<<" ";
            }std::cout<<"\n";
        }
    }
};

//---------------------------------------------------------------------------------------------------

void rotateFrame(Array2D& arr){
    container_v temp;

    for(int i=0; i<arr.cols; ++i)
        temp.push_back(arr.element(0, i));
    for(int i=1; i<arr.rows; ++i)
        temp.push_back(arr.element(i, arr.cols-1));
    for(int i=arr.cols-2; i>=0; --i)
        temp.push_back(arr.element(arr.rows-1, i));
    for(int i=arr.rows-2; i>0; --i)
        temp.push_back(arr.element(i, 0));

    int t = temp[0];
    temp.erase(temp.begin());
    temp.push_back(t);

    for(int i=0; i<arr.cols; ++i)
        {arr.element(0, i) = *temp.begin(); temp.erase(temp.begin());}
    for(int i=1; i<arr.rows; ++i)
        {arr.element(i, arr.cols-1) = *temp.begin(); temp.erase(temp.begin());}
    for(int i=arr.cols-2; i>=0; --i)
        {arr.element(arr.rows-1, i) = *temp.begin(); temp.erase(temp.begin());}
    for(int i=arr.rows-2; i>0; --i)
        {arr.element(i, 0) = *temp.begin(); temp.erase(temp.begin());}
}

//---------------------------------------------------------------------------------------------------

int main(){
    unsigned int t;
    std::cin>>t;

    for(int i=0; i<t; ++i){
        unsigned int l, k;
        std::cin>>l>>k;

        const int elementsAmount{l*k};
        container_v temp(elementsAmount);
        for(auto& it : temp){
            std::cin>>it;
        }

        Array2D arr(l,k,temp);
        rotateFrame(arr);
        std::cout<<"\n";
        arr.show();
        std::cout<<"\n";
    }

}



Wynalazłem coś takiego, sędzia mi to też przyjmuje. Wykorzystałem su swoją obecną wiedzę na temat OOP (przeciążeń operatorów jeszcze nie zastosowałem). Wymyśliłem też inny algorytm do przesunięcia ramki. Oczywiście sposób bez użycia dodatkowej tablicy jest najlepszy i go starannie przeanalizowałem, ale chciałem też pobawić się innymi sposobami.

Ten może nie jest zbyt elegancki ale zawsze warto było wypróbować to co mi wpadło do głowy, kopiujemy tu ramkę do wektora, a wektor przesuwamy o jedno miejsce w lewo. Potem zastępujemy ramkę jej nowszą wersją. Tak jak mówię sposób jest tylko dla testu. Ogólnie pomijając fakt że nie wykorzystałem do końca możliwości programowania obiektowego to kod jest nieco lepszy?

* A tu wersja z normalnym algorytmem:

#include <iostream>
#include <vector>

//---------------------------------------------------------------------------------------------------

using container_v = std::vector<int>;

class Array2D{

    container_v arr;
public:

    const int cols;
    const int rows;

    Array2D(int r, int c, container_v a) : rows(r), cols(c), arr(a) {}

    int& element(int row, int col){
        return arr[cols * row + col];
    }

    void show(){
        for(int i=0; i<rows; ++i){
            for(int j=0; j<cols; ++j){
                std::cout<<element(i,j)<<" ";
            }std::cout<<"\n";
        }
    }
};

//---------------------------------------------------------------------------------------------------

void rotateFrame(Array2D& arr){

    auto temp = arr.element(0,0);

    for(int i=0; i<arr.cols-1; ++i)
        arr.element(0, i) = arr.element(0, i+1);
    for(int i=0; i<arr.rows-1; ++i)
        arr.element(i, arr.cols-1) = arr.element(i+1, arr.cols-1);
    for(int i=arr.cols-1; i>0; --i)
        arr.element(arr.rows-1, i) = arr.element(arr.rows-1, i-1);
    for(int i=arr.rows-1; i>1; --i)
        arr.element(i, 0) = arr.element(i-1, 0);

    arr.element(1,0) = temp;
}

//---------------------------------------------------------------------------------------------------

int main(){
    unsigned int t;
    std::cin>>t;

    for(int i=0; i<t; ++i){
        unsigned int l, k;
        std::cin>>l>>k;

        const int elementsAmount{l*k};
        container_v temp(elementsAmount);
        for(auto& it : temp){
            std::cin>>it;
        }

        Array2D arr(l,k,temp);
        rotateFrame(arr);
        std::cout<<"\n";
        arr.show();
        std::cout<<"\n";
    }

}

 

+1 głos
odpowiedź 4 kwietnia 2018 przez mokrowski Mędrzec (155,460 p.)
Dobrze że udane zmaganie :) Wiedząc o tym że nie posługujesz się OOP i jeszcze ... "boisz się" algorytmów, mogę powiedzieć że całkiem nieźle :)

Prosiłeś o recenzję..

Zadał bym sobie następujące pytania co do tego zadania:

1. Minimalna ilość pamięci by wykonać zadanie rotacji samej ramki? Tyko dane ramki (czyli "brzegi")

2. Minimalna ilość pamięci by wykonać wyświetlenie wyniku? Dane zmienionej ramki i "wnętrza".

   To już istotna podpowiedź..

3. Struktury danych niezbędne by wykonać zadanie? 1-wymiarowe std::vector/tablice. Co do tablic, potrzebował bym dla samego siebie więcej argumentów by je wybrać bo kupuje się z nimi wiele problemów.

4. Czy trzeba kopiować/zamieniać dane w strukturze ramki? Nie, wystarczy je wpisać do struktury ramki już jako przesunięte.

5. Jak to wszystko wyświetlić? Odpowiednio nawigować 1 pętlą po przesuniętej już ramce wynikowej i strukturze danych wnętrza.

Co kłuje w oczy:

1. Podwójny wskaźnik. Jak by to było embedded i C, rozumiem. Czasem się broni nawet dla embedded w C++. Na poziomie takich aplikacji w C++ jest wiele sposobów by nie używać takich technik.

2. Szablon? A po co jeśli wiesz że zawsze int? Coś tym zyskujesz?

3. Referencja na podwójny wskaźnik to "już grubo" :/

4. Preferuj pre-(inkrementację/dekrementację) w indeksach pętli jeśli masz wybór, a tu masz. Dla POD'ów to nie ma znaczenia ale gdyby były to obiekty, operator będzie prostszy bo nie alokuje miejsca na kopię obiektu. Z tym zaleceniem jest wiele dyskusji ale to dobre przyzwyczajenie.

5. Duża ilość magic value. Jakieś -1, -2.... Można bez takich wygibasów np. mieć 2 indeksy co było by czytelniejsze.

Poczytaj o std::rotate, std::copy, std::transform

Jest dobrze :) Walcz :)
komentarz 4 kwietnia 2018 przez Jakub 0 Pasjonat (23,120 p.)

Dziękuje za wiele słusznych rad.

1) 2) 3) 5)

Wiem, chyba zmienię to na zwykłą tablice (czy vector) jednowymiarową. A do indeksów będę się dostawał poprzez:

[ (cols * row) + col ] 

------pytania z odpowiedzią-------

4)

Czy trzeba kopiować/zamieniać dane w strukturze ramki? Nie, wystarczy je wpisać do struktury ramki już jako przesunięte.

Jeśli chodzi o to:

int* result = createArr<int>(rows,col);
 
    for(int i=0; i<rows; i++){
        for(int j=0; j<col; j++){
            result[i][j] = arr[i][j];
        }
    }

To przekopiowałem dane z tablicy na której pracujemy do tablicy pomocniczej z takiego powodu że zmieniamy tylko ramki i środkowe pola tej tablicy (pomocniczej) pozostały by nieokreślone, a wtedy:

for(int i=0; i<rows; i++){
        for(int j=0; j<=col; j++){
            arr[i][j] = result[i][j];
        }
    }

Do orginalnej tablicy trafią śmieci. Przy moim rozwiązaniu problemu było to akurat konieczne.

---- Co kłuje  w oczy -----

1) 3)

Jak już wyżej napisałem zmienię podejście do rozwiązania problemu. Chociaż dzięki czemuś takiemu ćwiczę prace na wskaźnikach.

2)

Szablon? A po co jeśli wiesz że zawsze int? Coś tym zyskujesz?

To tak jak już pisałem w treści tematu 

Te funkcje są szablonami bo wcześniej zadanie planowałem rozwiązać inaczej (jeszcze chyba bardziej na około) i potrzebowałem tablicy struktur (a nie chciałem od nowa pisać kodu jej tworzenia).

 To fakt że już teraz nie są potrzebne, po prostu już tak zostały bo nie chciało  mi się ich usuwać (a raczej w niczym nie przeszkadzają ). No chyba że są powody dla których nie warto używać szablonów kiedy nie są one niezbędne.

4)

Wiem, słyszałem o tym wiele razy ale ciągle zapominam stosować :/

5)

Racja, sam się z tym gubiłem najbardziej ;)

 

 

0 głosów
odpowiedź 4 kwietnia 2018 przez Beginer Pasjonat (22,110 p.)
Ja przyglądałem się uważnie Twojemu wczorajszemu zadaniu (musiałem je nawet lekko uzupełnić, żeby w ogóle móc sprawdzać), i w tym widzę podobny mankament. W jednym i drugim zadaniu trzeba kilkakrotnie wprowadzać sporo różnych danych: liczbę testów, liczbę elementów, wyrazy tablic. Na konsoli użytkownika nie pojawiają się żadne opisy-żądania, co aktualnie należy wpisywać. Można się łatwo pogubić. Podobnie licho wygląda opis przy wyprowadzaniu wyników (a nawet zupełnie go nie ma). W każdym programie wyświetlenie wyników (z odpowiednim tytułem, w odpowiednim miejscu, formacie), to przecież najważniejsza sprawa.

Trochę mnie to dziwi, ponieważ cały kod jest napisany b.starannie, czytelnie, przestrzennie - wręcz wzorcowo (ostatniej linii oddzielającej, za main już bym nie umieszczał).

Jakość kodu zawsze jest ważna, ale użytkownik widzi tylko obsługę i działanie programu - to trzeba postawić jeszcze przed kodem.
2
komentarz 4 kwietnia 2018 przez damianeqe Gaduła (4,380 p.)
Sędzia spoj sprawdza tylko input i output, czy jest taki jak oczekuje, jeżeli dodasz w inpucie couta "Podaj t" to pomimo poprawnego rozwiązania problemu, sędzie nie zaliczy zadania.

 

Dla programów które są na potrzeby "człowieka" takie komunikaty są wskazane wręcz. :)
komentarz 4 kwietnia 2018 przez Jakub 0 Pasjonat (23,120 p.)

Dziękuje za odpowiedź,

Twojemu wczorajszemu zadaniu

Nie wiem o czym mowa :/

Jeśli chodzi o to że nie ma żadnych konkretnych informacji dla użytkownika to tak celowo zrobiłem, jest to zadanie do spoj'a i by mi wtedy sędzia nie zaliczył ;) Po za tym tu nie liczy się "szata graficzna". To jest jedynie demonstracja algorytmu. Bo to raczej żadnemu użytkownikowi prócz mi do ćwiczeń się nie przyda...

* Kiedy bym pisał aplikacje do praktycznych celów którą chce wydać (np w sfml czy Qt ) to oczywiście zadbanie o integracje z użytkownikiem było by znaczącym warunkiem jakości takowego oprogramowania.

komentarz 4 kwietnia 2018 przez Beginer Pasjonat (22,110 p.)
Czy zadanie z wyszukiwaniem elementu najbliższego średniej wyrazów tablicy nie było Twoje?
komentarz 4 kwietnia 2018 przez Jakub 0 Pasjonat (23,120 p.)
Aaa... racja, tylko odpowiadał ktoś inny dlatego nie skojarzyłem.
komentarz 4 kwietnia 2018 przez Beginer Pasjonat (22,110 p.)

W załączeniu zamieszczam wczorajsze zadanie z lekko uzupełnionym komentarzem w konsoli. Jest to ilustracja, o czym mówiłem w tej odpowiedzi.

#include <iostream>
#include <cmath>
using namespace std;

int returnArrayElement(int arr[], unsigned int n){
    double sum = 0; //suma elementow ciagu
    for(int i = 0; i < n; i++)
        sum += arr[i];
    double average = sum / n;

    int theSmallDiff = 0; //indeks tablicy najblizszy sredniej (poxczątkowo zerowy)

    for(int i = 1; i < n; i++){
        if(abs(average-arr[i]) < abs(average-arr[theSmallDiff]))   //wyszukujemy nowe minimum
            theSmallDiff = i;
    }
    return arr[theSmallDiff];
}

int main(){
    int t;
    cout << "ile bedzie testow (tablic)?  "; cin >> t;  //ile jest testow

    for(int i = 0; i < t; i++)
        {
        int n;
        cout << "ile liczb w tablicy?  "; cin >> n;  //ile jest liczb w jednej linii
        cout << "tablica #" << i + 1 << ", wprowadz kolejne liczby:" << endl;

        int* arr = new int[n];  //dynamiczna deklaracja tablicy

        for(int i = 0; i < n; i++)
        {
          cin >> arr[i];
        }

        cout << "Element najbizszy sredniej to: " << returnArrayElement(arr,n) << endl << endl;

        delete[] arr;  //usuniecie tablicy
        }

    return 0;
}

 

komentarz 4 kwietnia 2018 przez Jakub 0 Pasjonat (23,120 p.)
No tak, ale była mowa że dla zadań do spoj'a takich dodatkowych informacji dla użytkownika nie podajemy. Tu nawet nie trzeba nic wpisywać bo można przekierować z pliku dane wejściowe (np testowe z serwisu)  na których program ma pracować.

* po za tym raczej umiem używać cout'a ;)
1
komentarz 4 kwietnia 2018 przez Beginer Pasjonat (22,110 p.)
P.S. Drobna jeszcze uwaga. Zadanie, w którym jest podana maksymalna liczba elementów zwłaszcza, że jest niewielka (poniżej 100), nie wymaga dynamicznej alokacji pamięci.

Podobne pytania

0 głosów
2 odpowiedzi 1,270 wizyt
pytanie zadane 8 kwietnia 2018 w SPOJ przez Jakub 0 Pasjonat (23,120 p.)
0 głosów
0 odpowiedzi 242 wizyt
pytanie zadane 3 kwietnia 2018 w SPOJ przez Jakub 0 Pasjonat (23,120 p.)
0 głosów
3 odpowiedzi 243 wizyt
pytanie zadane 15 marca 2018 w C i C++ przez Jakub 0 Pasjonat (23,120 p.)

92,451 zapytań

141,261 odpowiedzi

319,073 komentarzy

61,853 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...