---
# System prepended metadata

title: Zajęcia 21.04.2021
tags: [xivlo]

---

###### tags: `xivlo`

# Zajęcia 21.04.2021

## Zadanie "Domino Jasia"
Liczby na kostce traktujemy jak wierzchołki w grafie, a samą kostkę jako połączenie między nimi.

Po wczytaniu krawędzi i tym samym stworzeniu grafu, możemy uruchomić dowolny algorytm przeszukiwania DFS/BFS od wierzchołka `p` i sprawdzić czy dotarł on do wierzchołka `k`.

Odpowiedź na pytanie czy istnieje droga między pechową liczbą `p`, a szczęśliwą `k`, możemy uzyskać także rozwiązując nasze zadanie za pomocą algorytmu wyznaczania MST. Jeśli użyjemy Union(x,y) na wszystkich kostkach domina [x|y], to dostaniemy spójne zbiory wierzchołków. Jest droga od `p` do `k`, jeśli oba te wierzchołki znajdują się w jednym zbiorze.

#### *ROZWIĄZANIE ZADANIA*
:::spoiler
```cpp=
#include <iostream>
#include <vector>
using namespace std;

vector<int> G[10004];
bool vis[10004];
int k;

void dfs(int v){
    if(v==k){
        cout<<"TAK\n";
        exit(0);
    }
    vis[v]=true;
    for(int s: G[v]){
        if(!vis[s]){
            dfs(s);
        }
    }
}

int main()
{
    int p,m,a,b;
    cin>>p>>k>>m;
    for(int i=0; i<m; i++){
        cin>>a>>b;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    dfs(p);
    cout<<"NIE\n";

    return 0;
}
```
:::

## Zadanie "Długie wakacje"
Tak jak powiedzieliśmy sobie w trakcie omówienia na lekcji, to zadanie może być w prosty sposób rozwiązane zachłannie.

Będziemy wybierać(zliczać) po kolei wycieczki na które może pojechać Jasiu, w kolejności terminu ich zakończenia. Gdyż jeśli wycieczka zakończyła się w dniu x to ma maksymalnie x dni długości. Możliwie krótkie i wcześnie kończące się wycieczki, będziemy zatem rozpatrywać najpierw i to jest własność, która jest dla nas porządana.

#### *ROZWIĄZANIE ZADANIA*
:::spoiler
```cpp=
#include <iostream>
#include <algorithm>
using namespace std;

pair<int, int> p[100003];

int main()
{
    int n;
    cin>>n;
    
    for(int i=0; i<n; i++){
        cin>>p[i].second>>p[i].first;
    }
    
    sort(p, p+n);
    
    int ile=1;
    int ost=0;
    for(int i=1; i<n; i++){
        if(p[i].second > p[ost].first){
            ile++;
            ost=i;
        }
    }
    
    cout<<ile<<"\n";

    return 0;
}
```
:::

## Zadanie "Jednowymiarowe rzutki"
Zadanie to proste wyszukiwanie binarne.

Przypomnę koncept wyszukiwania binarnego na dwóch prostych przykładach.
### Przykład 1
Grasz z drugą osobą w *Zgadnij liczbę*. Osoba ta myśli liczbę od 1 do $n$, a Ty musisz zgadnąć co to za liczba. Możesz zadawać osobie pytania, na które może odpowiadać tylko TAK/NIE. Dodatkowo chcesz być pewn_, że nie zadasz więcej niż $\lceil log_2(n)\rceil$ pytań.

```python=
def binary_search(start, koniec):
    lewy = start - 1
    prawy = koniec + 1
    
    while lewy + 1 < prawy:
        srodek = (lewy+prawy)/2
        if <czy środek jest >= od pomyślanej liczby?>:
            prawy = srodek
        else:
            lewy = srodek
            
    return <Ta liczba to prawy>
    

def main():
    p = 1
    n = <osoba mówi jaka jest maksymalna liczba>
    
    print("Twoja liczba to:", binary_search(p, n))
```


### Przykład 2
Franek ma swoim domu hodowlę królików - ma ich bardzo dużo! Weterynarz kazał mu co jakiś czas przyjeżdzać na kontrolę z pierwszym królikiem o wadze mniejszej niż $x$. Pomóż Frankowi szybko dowiadywać się z którym królikiem powinien jechać na kontrolę zdrowia.

*Wejście*
Dostajesz $n$ - liczbę królików, a następnie w $n$ liniach pary $w, p$, gdzie $w$ ($0<w\leq10^9$) to waga królika, a $p$ to jego imię. Następnie na wejściu pojawia się liczba $q$, a po niej $q$ zapytań z jedną liczbą $x$.

*Wyjście*
Twoim zadaniem jest wypisanie $q$ wierszy, w każdym należy wypisać imię pierwszego lżejszego niż $x$ królika. Jeśli nie ma takiego królika, należy wypisać pusty napis.

*Przykładowe wejście*
```
5
13 Jan
9 Jola
12 Joachim
3 Jurek
7 Joanna
3
10
2
15
```

*Przykładowe wyjście*
```
Jola

Jan
```

#### Rozwiązanie przykładu 2
```cpp=
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;

int n;
vector < pair<int, string> > kroliki;

string bs(int x){
    int lewy = 0;
    int prawy = n+1;
    
    while(lewy+1<prawy){
        int srodek = (lewy+prawy)/2;
        
        if( kroliki[srodek].first >= x ){
            prawy = srodek;
        }else{
            lewy = srodek;
        }
    }
    
    return kroliki[lewy].second;
}


int main(){
    int p,w,q,x;
    cin>>n;
    
    kroliki.push_back({0,""});
    for(int i=1; i<=n; i++){
        cin>>w>>p;
        kroliki.push_back({w,p});
    }
    
    sort(kroliki.begin(), kroliki.end());
    
    cin>>q;
    
    for(int i=0; i<q; i++){
        cin>>x;
        cout<<bs(x)<<"\n";
    }
    
    return 0;
}

```

#### *ROZWIĄZANIE ZADANIA*
:::spoiler
```cpp=
#include <iostream>
#include <algorithm>
// ↓ Definiuję sobie skrócone nazwy, by kod był czytelniejszy
#define fst first
#define snd second
using namespace std;

// tablica na nasze przedziały ((od, do), wartość)
pair< pair<int,int>, long long> przedzialy[100005];
int n;

// wyszukiwanie binarne przedziału
long long int bs(int x){
    // jako przedziały skrajne, wybieram te które oznaczają
    // wartości mniejesze od najbardziej skrajnej pary z 'lewej strony'
    // i analogicznie większe od najbardziej skrajnej pary z 'prawej strony'
    // tablicy przedziałów
    int l=0;
    int p=n+1;
    while(l+1<p){
        int s=(l+p)/2;
        if(x >= przedzialy[s].fst.fst && x <= przedzialy[s].fst.snd)
            // znalazłem przedział w którym zawiera się x
            return przedzialy[s].snd;
        if(x >= przedzialy[s].fst.snd){
            l=s;
        }else{
            p=s;
        }
    }
    // po wyjściu z pętli mam dwóch kandydatów na rozwiązanie - l i p
    
    // sprawdzam czy x zawiera się w l
    if (l != 0 && x >= przedzialy[l].fst.fst && x <= przedzialy[l].fst.snd)
        return przedzialy[l].snd;
        
    // sprawdzam czy x zawiera się w p
    if (p != n+1 && x >= przedzialy[p].fst.fst && x <= przedzialy[p].fst.snd)
        return przedzialy[p].snd;
        
    // teraz już wiem, że trafiono w miejsce spoza przedziałów z punktami 
    return 0;
}

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

    int q,t;
    cin>>n;
    for(int i=1; i<=n; i++){
        cin>>przedzialy[i].fst.fst>>przedzialy[i].fst.snd>>przedzialy[i].snd;
    }
    sort(przedzialy+1, przedzialy+n+1);

    cin>>q;
    for(int i=0; i<q; i++){
        cin>>t;
        cout<<bs(t)<<"\n";
    }


    return 0;
}
```
:::