###### 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;
}
```
:::