Optymalizacja zadania Skrzaty

Optymalizacja zadania Skrzaty
S7
  • Rejestracja:prawie 5 lat
  • Ostatnio:9 dni
  • Postów:354
0

Cześć mam takie zadanie:
Skrzaty
Limit pamięci: 64 MB

Zły smok Bitol najechał krainę skrzatów i wziął w niewolę jej mieszkańców. Przydzielił każdemu z n skrzatów inne stanowisko pracy i, samemu ległszy na stercie skradzionych kosztowności, jął leniwie nadzorować ich mozolne trudy.

Jako że Bitol jest wyjątkowo gnuśnym smokiem, nie obserwuje jednocześnie wszystkich poddanych. Zamiast tego cały czas przygląda się uważnie tylko skrzatom pracującym przy pewnej grupie stanowisk. W tym czasie wszystkie nieobserwowane przezeń skrzaty mogą spotykać się oraz dowolnie zamieniać się miejscami (Bitol nie jest w stanie zapamiętać, przy którym stanowisku pracował który skrzat). Co godzinę smok obraca głowę i zaczyna obserwować inny podzbiór skrzatów.

Skrzat Bajtazyl, któremu smok przydzielił stanowisko 1, chce zmobilizować towarzyszy niedoli do przeciwstawienia się Bitolowi. W tym celu musi najpierw spotkać się z sędziwym skrzatem Bajtomirem, któremu smok przydzielił stanowisko n. Przed Bajtazylem stoi zatem wyzwanie: odpowiednio zamieniając się z innymi skrzatami miejscami, winien jak najszybciej doprowadzić do sytuacji, w której on sam, ani stanowisko przy którym stoi aktualnie nasz śmiałek, ani stanowisko nie byłyby obserwowane przez smoka.

Twoim zadaniem jest ustalenie, kiedy najwcześniej może dojść do spotkania. Na szczęście wiadomo, że za godzin smok uśnie i wówczas wszystkie skrzaty będą w stanie komunikować się swobodnie.
Wejście

W pierwszym wierszu standardowego wejścia znajdują się dwie liczby całkowite n i m (1 <= n, m <= 1 000 000) oznaczające odpowiednio liczbę skrzatów oraz liczbę godzin pozostałych do czasu, aż Bitol zaśnie. W następnych wierszach znajdują się opisy grup stanowisk obserwowanych przez smoka w kolejnych godzinach, po jednym w wierszu. Na opis i-tej grupy stanowisk składa się liczba całkowita ki (1 <= ki <= n) oznaczająca liczbę obserwowanych stanowisk oraz uporządkowanych rosnąco liczb całkowitych ze zbioru {1...n} oznaczających numery obserwowanych stanowisk. Wszystkie liczby w wierszu poodzielane są pojedynczymi odstępami.

Możesz założyć, że k1 + k2 +km <= 2 000 000 .
Wyjście

W pierwszym i jedynym wierszu standardowego wyjścia Twój program powinien wypisać jedną liczbę całkowitą ze zbioru {0....m} - najmniejszą liczbę godzin, po której Bajtazyl może dotrzeć do Bajtomira.
Przykład

Dla danych wejściowych:

5 4
3 1 3 4
2 3 5
3 1 2 3
2 1 2

poprawną odpowiedzią jest:

2

Dla danych wejściowych:

6 2
4 2 3 4 5
6 1 2 3 4 5 6

poprawną odpowiedzią jest:

0

Dla danych wejściowych:

10 4
1 1
2 9 10
7 1 3 4 7 8 9 10
2 1 10

poprawną odpowiedzią jest:

4

Wyjaśnienie do przykładu:

W pierwszym z powyższych przykładów podczas pierwszej godziny swej wyprawy Bajtazyl nie może opuścić stanowiska o numerze , gdyż jest ono obserwowane przez smoka. Podczas drugiej godziny może on zamienić się miejscami ze skrzatem przy stanowisku o numerze . Dzięki temu dopiero na początku trzeciej godziny smok Bitol odwróci głowę ku stanowiskom o numerach , a Bajtazyl będzie mogł spotkać się z Bajtomirem.

W drugim z powyższych przykładów do spotkania może dojść natychmiast, gdyż w pierwszej godzinie smok nie patrzy na stanowiska Bajtazyla i Bitomira.

W trzecim przykładzie do spotkania może dojść dopiero wtedy, gdy Bitol uśnie.

I Mam taki kod

Kopiuj
#include <bits/stdc++.h>

using namespace std;

bool can_swap(vector<bool> & possible_pos, vector<bool> & watched_pos){
    for (int i = 0; i < possible_pos.size(); i++){
        if (possible_pos[i] == true && watched_pos[i] == false)
            return true;
    }
    return false;

}
void update_poss_pos(vector<bool> & possible_pos, vector<bool> & watched_pos){
    for (int i = 1; i < possible_pos.size(); i++){
        if (watched_pos[i] == false)
            possible_pos[i] = true;
    }
}


int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(nullptr);

    int n, m, k, ans;
    bool if_can_swap;
    cin >> n >> m;
    ans = m;

    vector<bool> possible_pos(n+1, false);
    possible_pos[1] = true;
    vector<vector<int>> dragon_watches(m);
    for (int i = 0; i < m; i++){
        cin >> k;
        dragon_watches[i].resize(k);
        for (int j = 0; j < k; j++)
            cin >> dragon_watches[i][j];
    }
    for (int i = 0; i < m; i++){
        vector<bool> watched_pos(n+1, false);
        for (int pos : dragon_watches[i])
            watched_pos[pos] = true;

        if_can_swap = can_swap(possible_pos, watched_pos);
        if (watched_pos[n] == false && if_can_swap){
            ans = i;
            break;
        }
        if (if_can_swap)
            update_poss_pos(possible_pos, watched_pos);
    }
    cout << ans;

  return 0;
}

niestety jest za wolny dla kilku testów, próbowałem też z setami ale czasy wychodziły jeszcze gorsze, jak zoptymalizować mój algorytm >


Competitive Google searcher
TS
  • Rejestracja:ponad 4 lata
  • Ostatnio:ponad 4 lata
  • Postów:394
2

Nie sądzę, że musisz zapisywać wszystkie "tury" do vectora. Wydaje się, że te wszystkie potrzebne rzeczy możesz sprawdzić w trakcie wczytywania wejścia. Poza tym na pewno dużo tracisz robiąc resize.

nalik
  • Rejestracja:około 9 lat
  • Ostatnio:prawie 2 lata
  • Postów:1039
1

Masz algorytm o złożoności O(mn), dla n, m <= 10^6. W najgorszym wypadku O(10^12). Masz też podpowiedź, że suma ilości obserwowanych pozycji we wszystkich m turach jest mniejsza od 2*10^6. A więc jest rzędu O(n).
Założyłbym, że trzeba zbić tą złożoność.

Można próbować O(m logn) korzystając na przykład z drzew segmentowych ;). Ciąg obserwowanych pozycji przecież można zamienić na ciąg nie obserwowanych przedziałów. W drzewie przedziałowym można zaznaczać te przedziały, które są osiągalne, zaczynając od 1. Jeżeli nowy przedział łączyłby się z jakimś przedziałem osiągalnym to oznaczamy go jako osiągalny. Gdy pozycja n (czyli przedział [n, n] będzie osiągalny, to algorytm się kończy.
Drzewo (przedział, przedział), (=, max) powinno dać radę.

EDIT: Wrzuciłem to do drzewa przedziałowego i przechodzi wszystkie testy.

edytowany 9x, ostatnio: nalik
S7
  • Rejestracja:prawie 5 lat
  • Ostatnio:9 dni
  • Postów:354
0

@tsz spróbowałem tak:

Kopiuj
#include <bits/stdc++.h>

using namespace std;

int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(nullptr);

    int n, m, k, ans, i, pos, watch_poss_pos, number_of_poss_pos;
    bool if_can_swap;
    cin >> n >> m;
    ans = m;
    bool * possible_pos = new bool[n+1];
    possible_pos[1] = true;
    bool * watched_pos = new bool[n+1];
    for (int u = 2; u <= n; u++)
        possible_pos[u] = false;

    number_of_poss_pos = 1;
    i = 0;
    while ( i < m && ans == m){
        for (int u = 0; u <= n; u++)
            watched_pos[u] = false;
        watch_poss_pos = 0;
        cin >> k;
        for (int j = 0; j < k; j++){
            cin >> pos;
            watched_pos[pos] = true;
            if (possible_pos[pos] == true)
                watch_poss_pos++;
        }

        if (watch_poss_pos < number_of_poss_pos && watched_pos[n] == false){
            ans = i;
        }

        if (watch_poss_pos < number_of_poss_pos){
            for(int x = 1; x <= n; x++){
                if (watched_pos[x] == false && possible_pos[x] == false){
                    possible_pos[x] = true;
                    number_of_poss_pos++;
                }

            }
        }
        i++;
    }
    while (i < m){
        cin >> k;
        for (int j = 0; j < k; j++)
            cin >> pos;
        i++;
    }
    cout << ans;

  return 0;
}

Polepszyło to mój czas, jednak algorytm dalej za wolny idę znowu oglądać pana Radoszewskiego ;)


Competitive Google searcher
nalik
Generalnie drzewo statyczne odpytywane i uaktualnianie rekurencyjnie się ledwie mieściło przy ostatnim teście.
S7
  • Rejestracja:prawie 5 lat
  • Ostatnio:9 dni
  • Postów:354
0

W drzewie przedziałowym można zaznaczać te przedziały, które są osiągalne, zaczynając od 1. Jeżeli nowy przedział łączyłby się z jakimś przedziałem osiągalnym to oznaczamy go jako osiągalny.

Nie rozumiem, w przypadku gdy jedynym możliwym przedziałem jest 1 i gdy smok obserwuje pozycje 2 3 5, osiągalny przedział to [4, 4] który nie łączy się z przedziałem [1, 1] więc według tego co napisałeś to nie dodajemy go, a przecież powinniśmy dodać przedział [4, 4] do osiągalnych


Competitive Google searcher
MarekR22
ja rozumiem treść zadania tak, że przejście do innego stanowiska jest dowolne (nie musi być sąsiednie) dopóki oba (docelowe i źródłowe) nie są obserwowane.
nalik
Tak, trzeba zrobić drobną modyfikację, zapomniałem edytować post . Mea culpa. Wystarczy, że którykolwiek przedział w danej iteracji jest osiągalny. Bo jeżeli którykolwiek jest osiągalny na podstawie wcześniejszych iteracji, tzn że da się od niego zacząć obecną iterację i dostać do każdego innego osiągalnego przedziału z obecnej tury.
S7
  • Rejestracja:prawie 5 lat
  • Ostatnio:9 dni
  • Postów:354
0

Okazało się że nie trzeba tworzyć drzewa segmentowego, nie wiem jak ale wgl nie zwróciłem uwagi że pozycje oglądane przez smoka są posortowane, znalazłem kod w internecie:

Kopiuj
/**
 * VI Olimpiada Informatyczna Gimnazjalistów
 * Zadanie: Skrzaty
 * Wynik 100/100
 * Wykonał: Marcin Wątroba
 * http://main.edu.pl/pl/archive/oig/6/skr
 */

#include <cstdlib>
#include <cstdio>
#include <vector>
#include <iostream>

using namespace std;

struct przed {
    int p;
    int k;
};

int wbez(int a) {
    if (a > 0)return a;
    else return -1 * a;
}

bool czy_wsp(int *tab, int dl, vector<przed> prz[1]) {
    int ltab = 0; // licznik tablicy
    int lvec = 0; // licznik vectora
    bool wynik = false;
    int ostwprz = -1;
    for (ltab; ltab < dl; ltab++) {
        //DOBRA FUNKCJA
        while (true) {
            if (lvec == prz[0].size()) {
                lvec--;
                break;
            } else if (tab[ltab] >= prz[0][lvec].p && tab[ltab] <= prz[0][lvec].k)
                break;
            else if (tab[ltab] < prz[0][lvec].p)
                break;
            if (ltab == 0)
                wynik = true;
            else if (-1 * tab[ltab - 1] != prz[0][lvec].k && tab[ltab - 1] < 0)
                wynik = true;
            else if (tab[ltab] > prz[0][lvec].k && tab[ltab - 1] < prz[0][lvec].k && tab[ltab - 1] > 0)
                wynik = true;
            lvec++;
        }
        if (tab[ltab] >= prz[0][lvec].p && tab[ltab] <= prz[0][lvec].k) {
            if (tab[ltab] - 1 >= prz[0][lvec].p && ltab > 0)
                if (tab[ltab] - 1 != tab[ltab - 1] * (-1))
                    wynik = true;
            tab[ltab] *= -1;
        }
    }
    if (wbez(tab[dl - 1]) < prz[0][prz[0].size() - 1].k) {
        wynik = true;
    }
    for (int a = 0; a < dl; a++)
        if (tab[a] < 0)tab[a] = 0;
    return wynik;
}

void nzbior(int *tab, int dl, vector<przed> prz[1], int n) {
    vector<przed> tym;
    int ltab;
    przed pom;
    pom.p = 1;
    for (int ltab = 0; ltab <= dl; ltab++) {
        if (ltab == 0)
            pom.p = 1;
        else
            pom.p = tab[ltab - 1] + 1;
        while (ltab != dl && tab[ltab] == 0)
            ltab++;
        if (ltab != dl)
            pom.k = tab[ltab] - 1;
        else
            pom.k = n;
        if (pom.p <= pom.k) {
            tym.push_back(pom);
        }
    }
    prz[0].assign(tym.begin(), tym.begin() + tym.size());
}

int main(int argc, char *argv[]) {
    int n, m;
    scanf("%d%d", &n, &m);
    int *dl = new int[m];
    int **obs = new int *[m];
    vector<przed> prz[1];
    przed pom = {1, 1};
    prz[0].push_back(pom);
    int i;
    bool wyn = false;
    for (i = 0; i < m; i++) {
        scanf("%d", &dl[i]);
        obs[i] = new int[dl[i]];
        for (int a = 0; a < dl[i]; a++)
            scanf("%d", &obs[i][a]);
        if (czy_wsp(obs[i], dl[i], prz)) {
            nzbior(obs[i], dl[i], prz, n);
        }
        if (prz[0][prz[0].size() - 1].k == n) {
            cout << i;
            wyn = true;
            break;
        }
    }

    if (!wyn)
        cout << m;

    return EXIT_SUCCESS;
}

trochę mi zajęło żeby ogarnąć o co tutaj wgl chodzi, ale pierwsza funkcja sprawdza czy można stworzyć nowy zbiór i zaznacza wszystkie obserwowane z możliwych pozycji (wartość * -1) a druga tworzy nowy zbiór dostępnych przedziałów, spróbowałem napisać swój, wydaje mi się bardziej czytelny program, żeby lepiej zrozumieć jak to zadanie rozwiązać

Kopiuj
#include <bits/stdc++.h>

using namespace std;

class Interval{
public:
    int beg;
    int end;

    Interval(int beg=0, int end=0){
        this->beg = beg;
        this->end = end;
    }
};

void show_poss_inters(vector<Interval> v){
    cout << "[" << " ";
    for (Interval i : v)
        cout << "(" << i.beg << "," << " " << i.end << ")" << " ";
    cout << "]" << endl;
}

void show_d_w(vector<int> & d_w, int d_w_len){
    for (int i = 0; i < d_w_len; i++)
        cout << d_w[i] << " ";
    cout << endl;
}
bool can_meet(vector<int> & drag_watch, int d_w_len, vector<Interval> & poss_in, int p_i_len){
    if (drag_watch[d_w_len - 1] < poss_in[p_i_len - 1].end)
        return true;

    int p_i_iter = 0;

    for (int d_w_iter = 0; d_w_iter < d_w_len; d_w_iter++){
        while (p_i_iter < p_i_len){
            if (drag_watch[d_w_iter] >= poss_in[p_i_iter].beg && drag_watch[d_w_iter] <= poss_in[p_i_iter].end){
                if (drag_watch[d_w_iter] - 1 >= poss_in[p_i_iter].beg && d_w_iter > 0)
                    if (drag_watch[d_w_iter] - 1 != abs(drag_watch[d_w_iter - 1]))
                        return true;
                drag_watch[d_w_iter] *= -1;
            }
            else if (drag_watch[d_w_iter] > poss_in[p_i_iter].beg){
                if (d_w_iter == 0)
                    return true;
                if (abs(drag_watch[d_w_iter - 1]) != poss_in[p_i_iter].end && drag_watch[d_w_iter - 1] < 0)
                    return true;
                else if (drag_watch[d_w_iter] > poss_in[p_i_iter].end &&
                         drag_watch[d_w_iter - 1] < poss_in[p_i_iter].end && drag_watch[d_w_iter - 1] > 0)
                    return true;
            }
            p_i_iter++;
        }
        p_i_iter--;
    }
    return false;
}

void select_all_belonging_to_poss_intervals(vector<int> & drag_watch, int d_w_len, vector<Interval> & poss_in, int p_i_len){
    int p_i_iter = 0;
    for (int d_w_iter = 0; d_w_iter < d_w_len; d_w_iter++){
        while (p_i_iter < p_i_len){
            if (drag_watch[d_w_iter] < 0 || drag_watch[d_w_iter] >= poss_in[p_i_iter].beg && drag_watch[d_w_iter] <= poss_in[p_i_iter].end){
                drag_watch[d_w_iter] = 0;
                break;
            }
            p_i_iter++;
        }
    }
}

void update_poss_inters(vector<int> & drag_watch, int d_w_len, vector<Interval> & poss_in, int p_i_len, int last_gnome){
    poss_in.clear();
    select_all_belonging_to_poss_intervals(drag_watch, d_w_len, poss_in, p_i_len);
    if (drag_watch[d_w_len - 1] != last_gnome){
        poss_in.push_back(Interval(1, last_gnome));
        return;
    }
    Interval helper;
    int d_w_iter = 0;
    while (d_w_iter <= d_w_len){
        if (d_w_iter == 0)
            helper.beg = 1;
        else
            helper.beg = drag_watch[d_w_iter - 1] + 1;
        while (d_w_iter != d_w_len && drag_watch[d_w_iter] == 0)
            d_w_iter++;
        if (d_w_iter != d_w_len)
            helper.end = drag_watch[d_w_iter] - 1;
        else
            helper.end = last_gnome;
        if (helper.beg <= helper.end)
            poss_in.push_back(helper);
        d_w_iter++;
    }

}



int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(nullptr);
    int n, m, k, ans;
    cin >> n >> m;
    ans = m;
    vector<vector<int>> dragon_watches(m);
    vector<Interval> poss_inters;
    poss_inters.push_back(Interval(1,1));
    for (int i = 0; i < m; i++){
        cin >> k;
        dragon_watches[i].reserve(k);
        for (int j = 0; j < k; j++)
            cin >> dragon_watches[i][j];
        if (can_meet(dragon_watches[i], k, poss_inters, poss_inters.size()))
            update_poss_inters(dragon_watches[i], k, poss_inters, poss_inters.size(), n);
        if (poss_inters[poss_inters.size() - 1].end == n){
            ans = i;
            break;
        }

    }
    cout << ans;
  return 0;
}

niestety nie przechodzi wszystkich testów (choć ma niezłą szybkość, ostatni test rozwiązuje dobrze a jego czas to 1.00s/3.00s), gdzie robię błąd ?


Competitive Google searcher
edytowany 2x, ostatnio: Suchy702
nalik
Nie wiem, ale jak chcesz to mogę udostępnić swoje rozwiązanie z użyciem drzewa.
S7
Chętnie zobaczę :D
nalik
  • Rejestracja:około 9 lat
  • Ostatnio:prawie 2 lata
  • Postów:1039
1

No, ok. Z drzewem wygląda tak:

Kopiuj
#include <algorithm>
#include <iostream>
#include <limits>
#include <vector>
using namespace std;

constexpr inline uint64_t ceil_pow2(uint64_t x) {
    uint64_t power = 1;
    while(power < x)
        power *= 2;
    return power;
}

class SegmentTree {
    struct Node { int val; int max; };
    vector<Node> nodes_;
    int lo_;
    int hi_;

public:
    SegmentTree(int lo, int hi) {
        const size_t count = ceil_pow2(hi - lo);
        nodes_.resize(2 * count, Node{ 0, numeric_limits<int>::min() });
        lo_ = lo;
        hi_ = lo_ + count;
    }

    inline void set(int lo, int hi, int val) {
        set(lo, hi, 1, lo_, hi_, val);
    }

    inline int query_max(int lo, int hi) const {
        return query_max(lo, hi, 1, lo_, hi_);
    }

private:
    void set(int lo, int hi, int node, int node_lo, int node_hi, int val) {
        const auto node_mid = node_lo + (node_hi - node_lo) / 2;

        if (lo <= node_lo && node_hi <= hi) {
            nodes_[node].val = val;
            nodes_[node].max = max(nodes_[node].max, val);
            return;
        }

        if (lo < node_mid) {
            set(lo, hi, 2*node, node_lo, node_mid, val);
            nodes_[node].max = max(nodes_[node].max, nodes_[2*node].max);
        }
        if (node_mid < hi) {
            set(lo, hi, 2*node + 1, node_mid, node_hi, val);
            nodes_[node].max = max(nodes_[node].max, nodes_[2*node + 1].max);
        }
    }

    int query_max(int lo, int hi, int node, int node_lo, int node_hi) const {
        const auto node_mid = node_lo + (node_hi - node_lo) / 2;

        if (lo <= node_lo && node_hi <= hi) {
            return nodes_[node].max;
        }

        int result = nodes_[node].val;
        if (lo < node_mid)
            result = max(result, query_max(lo, hi, 2*node, node_lo, node_mid));
        if (node_mid < hi)
            result = max(result, query_max(lo, hi, 2*node + 1, node_mid, node_hi));
        return result;
    }
};

bool move_exist(const vector<int> &watched, const SegmentTree &reachable) {
    for (size_t i = 1; i < watched.size(); ++i) {
        const auto a = watched[i - 1] + 1;
        const auto b = watched[i];
        if (a < b && (reachable.query_max(a, b) > 0)) {
            return true;
        }
    }
    return false;
}

void connect_reachable(const vector<int> &watched, SegmentTree &reachable) {
    for (size_t i = 1; i < watched.size(); ++i) {
        const auto a = watched[i - 1] + 1;
        const auto b = watched[i];
        if (a < b) {
            reachable.set(a, b, 1);
        }
    }
}

int main(int argc, char const *argv[]) {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    size_t n, m;
    cin >> n >> m;

    SegmentTree reachable{1, (int)n + 1};
    reachable.set(1, 2, 1);

    vector<int> watched;
    watched.reserve(2 * n);

    size_t iter;
    for (iter = 0; iter < m; iter++) {
        size_t num_watched;
        cin >> num_watched;

        watched.resize(num_watched + 2);
        watched[0] = 0; // start guardian
        for (size_t i = 1; i <= num_watched; i++) {
            cin >> watched[i];
        }
        watched[num_watched + 1] = (int)n + 1; // end guardian

        if (move_exist(watched, reachable)) {
            connect_reachable(watched, reachable);
        }

        if (reachable.query_max(n, n + 1) > 0 && watched[num_watched] != n) {
            break;
        }
    }

    cout << iter << endl;

    return 0;
}
edytowany 2x, ostatnio: nalik
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)