Upload
others
View
1
Download
0
Embed Size (px)
Citation preview
2010-12-01
1
Ogólne wiadomości o grafach
Algorytmy i struktury danychWykład 5.
Rok akademicki: 2010/2011
2
Pojęcie grafu
• Graf – zbiór wierzchołków połączonych za pomocą krawędzi.
• Podstawowe rodzaje grafów:– grafy nieskierowane,
– grafy skierowane.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
2
3
Graf nieskierowany
• Graf nieskierowany G = (V, E), gdzie:– V – zbiór wierzchołków,
– E – zbiór krawędzi, czyli zbiór nieuporządkowanych par wierzchołków o postaci (u, v), gdzie u, v V i u ≠ v (w grafie nieskierowanym nie mogą występowad pętle, czyli połączenie łączące wierzchołek z samym sobą).
• Graf nieskierowany nazywany jest grafem prostym.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
Pojęcia związane z grafami prostymi (nieskierowanymi)
• ścieżka – ciąg połączonych kolejno ze sobą wierzchołków,
• długośd ścieżki – liczba krawędzi wchodzących w skład ścieżki,
• ścieżka prosta – jeśli wszystkie wchodzące w jej skład wierzchołki są różne (dopuszcza się jedynie, aby pierwszy i ostatni wierzchołek był identyczny)
• graf spójny – jeśli dla każdej pary wierzchołków istnieje łącząca je ścieżka
4Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
3
Pojęcia związane z grafami prostymi (nieskierowanymi)
• krawędź (u, v) nazywana jest krawędzią przylegającą do wierzchołków u oraz v lub krawędzią incydentną z tymi wierzchołkami
• stopieo wierzchołka – liczba incydentnych z nim krawędzi
• cykl – ścieżka łącząca wierzchołek z samym sobą
• graf cykliczny – graf zawierający co najmniej jeden cykl
5Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
6
Graf skierowany
• Graf skierowany (digraf) G = (V, E) to struktura składająca się ze zbioru wierzchołków V oraz zbioru krawędzie (zwanych także łukami).
• Krawędź jest uporządkowaną parą wierzchołków (u, v) – u jest wierzchołkiem początkowym, a v wierzchołkiem koocowym krawędzi.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
4
7
Graf ważony
• Graf ważony – graf, w którym z każdą krawędzią skojarzony jest parametr numeryczny zwany wagą.
• Grafy ważone mogą byd grafami nieskierowanymi lub skierowanymi.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
Reprezentacja grafów – 1/2
• reprezentacja za pomocą macierzy sąsiedztwa (macierzy przyległości)
8
A
C
B A B C
A 0 1 1
B 1 0 0
C 1 0 0
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
5
Reprezentacja grafów – 2/2
A
C
B A B C
B A
C A
9
• reprezentacja listowa
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
10
Metody przeszukiwania grafu
• Wyróżnia się dwie podstawowe metody przeszukiwania grafu (wędrówki po grafie):– DFS – depth-first search – przeszukiwanie „wgłąb” grafu
– BFS – breadth-first search – przeszukiwanie „wszerz” grafu
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
6
11
Przeszukiwanie wgłąb grafu
1. Jeśli jest to możliwe, to należy przejśd do przyległego nieodwiedzonego wierzchołka; wierzchołek ten staje się wierzchołkiem bieżącym; wierzchołek ten umieszczany jest na stosie
2. jeśli wykonanie kroku 1. nie jest możliwe usuwamy jeden element ze stosu; element znajdujący się na wierzchołku staje się elementem bieżącym
3. jeśli wykonanie powyższych reguł nie jest możliwe, to oznacza to koniec zadania
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
12
Przeszukiwanie wgłąb grafu – przykład
Rezultat przeszukiwania DFS:A, B, D, F, E, C, G.
lubA, E, F, B, D, C, G Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
7
13
Przeszukiwanie wszerz grafu
1. Jeśli jest to możliwe, to należy odwiedzid kolejny, wcześniej nieodwiedzony wierzchołek, przyległy do wierzchołka bieżącego. Odwiedzony wierzchołek umieszczany jest w kolejce. Nie następuje zmiana wierzchołka bieżącego.
2. Gdy nie ma już kolejnych nieodwiedzonych wierzchołków, to z kolejki pobieramy pierwszy element. Staje się on wierzchołkiem bieżącym.
3. Procedura kooczy swoje działania, gdy nie można zastosowad powyższych reguł – brak nieodwiedzonych wierzchołków i brak elementów w kolejce.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
14
Przeszukiwanie wszerz grafu - przykład
kolejność wskazywana przez numery wierzchołków
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
8
15
Algorytm Dijkstry
• Cel algorytmu: wyznaczanie najkrótszej drogi prowadzącej z rozpatrywanego wierzchołka do każdego innego
• Autor: Edsger Dijkstra, 1959
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
16
Podstawowe założenia algorytmu
• działanie algorytmu rozpoczyna się od wskazania wierzchołka początkowego
• w kolejnych krokach przetwarzane są kolejne wierzchołki. Rozpatrywane są dwa zbiory wierzchołków:– S – wierzchołki przetworzone– V – wierzchołki nieprzetworzone
• algorytm korzysta z dwóch wektorów:– d[i] – długośd drogi od wierzchołka początkowego do i-tego
wierzchołka – p[i] – informacja o najkrótszej ścieżce (indeks wierzchołka
bezpośrednio poprzedzającego i-ty wierzchołek – na najkrótszej ścieżce)
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
9
17
Algorytm Dijkstry
0
2
4
3
1
8010
10
10
10
40
20
20
20
30 V d(0,v) p(v) S/V
0 0 0 S
1 80 0 V
2 40 0 V
3 0 V
4 0 V
Inicjalizacja obliczeoElement bieżący: 0
Spośród elementów zbioru Vwyszukiwany jest ten, do któregoprzejście związane jest z minimalnymkosztem (dla v = 2). Element tenprzesuwany jest do zbioru S.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
18
Algorytm Dijkstry
0
2
4
3
1
8010
10
10
10
40
20
20
20
30
V d(v) p(v) S/V
0 0 0 S
1 80 0 V
2 40 0 S
3 60 2 V
4 50 2 V
Bieżący węzeł: 2Koszt dotarcia do bieżącego węzła: 40jeżelikoszt dotarcia do bieżącego węzła +koszt dotarcia od bież. do v-tego <dotychczas określony koszt dotarciado v-tego węzła
tomodyfikacja d(v)
Wybór kolejnego el. o min. koszcie (4)
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
10
19
Algorytm Dijkstry
0
2
4
3
1
8010
10
10
10
40
20
20
20
30
V d(v) p(v) S/V
0 0 0 S
1 80 0 V
2 40 0 S
3 60 2 V
4 50 2 S
Bieżący węzeł: 4Koszt dotarcia do bieżącego węzła: 50jeżelikoszt dotarcia do bieżącego węzła +koszt dotarcia od bież. do v-tego <dotychczas określony koszt dotarciado v-tego węzła
tomodyfikacja d(v)
Wybór kolejnego el. o min. koszcie (3)
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
20
Algorytm Dijkstry
0
2
4
3
1
8010
10
10
10
40
20
20
20
30
V d(v) p(v) S/V
0 0 0 S
1 70 3 V
2 40 0 S
3 60 2 S
4 50 2 S
Bieżący węzeł: 3Koszt dotarcia do bieżącego węzła: 60jeżelikoszt dotarcia do bieżącego węzła +koszt dotarcia od bież. do v-tego <dotychczas określony koszt dotarciado v-tego węzła
tomodyfikacja d(v)
Wybór kolejnego el. o min. koszcie (1)
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
11
21
Algorytm Dijkstry
0
2
4
3
1
8010
10
10
10
40
20
20
20
30
V d(v) p(v) S/V
0 0 0 S
1 70 3 S
2 40 0 S
3 60 2 S
4 50 2 S
Wyniki koocowe:
0-1: koszt: 70 (0-2-3-1)0-2: koszt: 40 (0-2)0-3: koszt: 60 (0-2-3)0-4: koszt: 50 (0-2-4)
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
Zastosowanie algorytmu Dijkstry
• Open Shortest Path First (OSPF) – protokół routinguwewnętrznego wykorzystywany w sieci Internet (obok protokołu RIP). Wyznaczanie optymalnych tras przesyłania pakietów realizowane jest przez routery.
22Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
12
23
Minimalne drzewo rozpinające
• Drzewem rozpinające grafu G nazywamy drzewo, które zawiera wszystkie wierzchołki grafu G, zaś zbiór krawędzi drzewa jest podzbiorem zbioru krawędzi grafu.
• Minimalne drzewo rozpinające – drzewo rozpinające w grafie ważonym, dla którego suma wag jest najmniejsza z możliwych
0
2
4
3
1
8010
10
10
10
40
20
20
20
30
0
2
4
3
1
8010
10
10
10
40
20
20
20
30
koszt: 150
koszt: 80
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
24
Algorytm Prima
• Algorytm wyznaczania minimalnego drzewa rozpinającego
• R. C. Prim, 1957
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
13
25
Podstawowe założenia algorytmu
• działanie algorytmu rozpoczyna się od wskazania wierzchołka początkowego
• w kolejnych krokach przetwarzane są kolejne wierzchołki. Rozpatrywane są dwa zbiory wierzchołków:– S – wierzchołki przetworzone– V – wierzchołki nieprzetworzone
• algorytm korzysta z dwóch wektorów:– d[i] – długośd drogi od wierzchołka bieżącego do i-tego
wierzchołka – p[i] – informacja o kolejnej krawędzi dodawanej do
minimalnego drzewa rozpinającego (indeks wierzchołka bezpośrednio poprzedzającego i-ty wierzchołek)
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
26
Algorytm Prima
0
2
4
3
1
8010
10
10
10
40
20
20
20
30 V d(0,v) p(v) S/V
0 0 0 S
1 80 0 V
2 40 0 V
3 0 V
4 0 V
Inicjalizacja obliczeo
Spośród elementów zbioru Vwyszukiwany jest ten, do któregoprzejście związane jest z minimalnymkosztem (dla v = 2). Element tenprzesuwany jest do zbioru S.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
14
27
Algorytm Prima
0
2
4
3
1
8010
10
10
10
40
20
20
20
30
V d(v) p(v) S/V
0 0 0 S
1 80 0 V
2 40 0 S
3 20 2 V
4 10 2 V
Bieżący węzeł: 2jeżelikoszt dotarcia od bież. do v-tego <dotychczas określony koszt dotarciado v-tego węzła
tomodyfikacja d(v)
Wybór kolejnego el. o min. koszcie (4)
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
28
Algorytm Prima
0
2
4
3
1
8010
10
10
10
40
20
20
20
30
V d(v) p(v) S/V
0 0 0 S
1 80 0 V
2 40 0 S
3 20 2 V
4 10 2 S
Bieżący węzeł: 4jeżelikoszt dotarcia od bież. do v-tego <dotychczas określony koszt dotarciado v-tego węzła
tomodyfikacja d(v)
Wybór kolejnego el. o min. koszcie (3)
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
15
29
Algorytm Prima
0
2
4
3
1
8010
10
10
10
40
20
20
20
30
V d(v) p(v) S/V
0 0 0 S
1 10 3 V
2 40 0 S
3 20 2 S
4 10 2 S
Bieżący węzeł: 3Koszt dotarcia do bieżącego węzła: 60jeżelikoszt dotarcia od bież. do v-tego <dotychczas określony koszt dotarciado v-tego węzła
tomodyfikacja d(v)
Wybór kolejnego el. o min. koszcie (1)
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
30
Algorytm Prima
0
2
4
3
1
8010
10
10
10
40
20
20
20
30
V d(v) p(v) S/V
0 0 0 S
1 10 3 S
2 40 0 S
3 20 2 S
4 10 2 S
Wyniki koocowe:
Zbiór krawędzi:3 – 10 – 22 – 32 – 4Koszt drzewa: 80
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
16
Implementacja drzew i grafów
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 31
Biblioteka JDSL – www.jdsl.org
32Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
17
Przykładowy program
import jdsl.core.api.*;import jdsl.core.ref.*;
public class Tree01 {
//puste drzewostatic Tree pusteDrzewo () {
Tree t = new NodeTree();return t;
}
//drzewo - tylko korzenstatic Tree tylkoKorzen () {
Tree t = new NodeTree();t.replaceElement(t.root(),"Korzeo");return t;
}
33Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
...
//drzewo reprezentujace dni tygodniastatic Tree dniTygodnia () {
Tree t = new NodeTree();t.replaceElement(t.root(),"Tydzieo");t.insertLastChild(t.root(),"Poniedziałek");t.insertLastChild(t.root(),"Wtorek");t.insertLastChild(t.root(),"Środa");t.insertLastChild(t.root(),"Czwartek");t.insertLastChild(t.root(),"Piątek");t.insertLastChild(t.root(),"Sobota");t.insertLastChild(t.root(),"Niedziela");return t;
}
34Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
18
...
static Tree rok() {Tree t = new NodeTree();Position p;
t.replaceElement(t.root(),"Rok");
p = t.insertLastChild(t.root(),"Zima");t.insertLastChild(p,"Styczeo");t.insertLastChild(p,"Luty");t.insertLastChild(p,"Marzec");
p = t.insertLastChild(t.root(),"Wiosna");t.insertLastChild(p,"Kwiecieo");t.insertLastChild(p,"Maj");t.insertLastChild(p,"Czerwiec");
35Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
...
p = t.insertLastChild(t.root(),"Lato");t.insertLastChild(p,"Lipiec");t.insertLastChild(p,"Sierpieo");t.insertLastChild(p,"Wrzesieo");
p = t.insertLastChild(t.root(),"Jesieo");t.insertLastChild(p,"Październik");t.insertLastChild(p,"Listopad");t.insertLastChild(p,"Grudzieo");
return t;}
public static void main(String [] args) {...}} // koniec programu
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 36
2010-12-01
19
37
Poruszanie się po drzewie
• sposób poruszania się po drzewie – kolejnośd odwiedzania węzłów
• trzy podstawowe metody poruszania się po drzewie:– preorder,
– postorder,
– inorder.
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
Tworzenie przykładowego drzewa
static Tree liczby() {Tree t = new NodeTree();Position p, r;
t.replaceElement(t.root(),new Integer(1));
t.insertLastChild(t.root(), new Integer(2));
p = t.insertLastChild(t.root(), new Integer(3));
r = t.insertLastChild(p, new Integer(5));t.insertLastChild(r, new Integer(8));t.insertLastChild(r, new Integer(9));
r = t.insertLastChild(p, new Integer(6));t.insertLastChild(r, new Integer(10));
p = t.insertLastChild(t.root(), new Integer(4));t.insertLastChild(p, new Integer(7));
return t;}
38
1
2 43
5 6 7
1098
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
20
39
Metoda preorder 1/2
1
2 43
5 6 7
1098
Metoda preorder - rozpoczyna się od korzenia drzewa, a następnie odwiedzane są wszystkie jego poddrzewa w kolejności od lewej do prawej strony
Przechodzenie preorder: 1 2 3 5 8 9 6 10 4 7
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
Metoda preorder 2/2
static void preOrder(Tree t, Position p) {
System.out.print(p.element() + " ");
try { p = t.firstChild(p);}catch (Exception e) {p = null;}
while (p != null){
preOrder(t, p);try { p = t.siblingAfter(p);}catch (Exception e) {p = null;}
}}
40Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
21
41
Metoda postorder 1/2
1
2 43
5 6 7
1098
Metoda postorder - w pierwszej kolejności odwiedzane są wszystkie poddrzewa w kolejności od lewej do prawej strony, a następnie odwiedzany jest korzeo drzewa.
Przechodzenie postorder: 2 8 9 5 10 6 3 7 4 1
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
42
Metoda postorder 2/2
static void postOrder(Tree t, Position p) {
Position p0 = p;try {p0 = t.firstChild(p0);}catch (Exception e) {p0 = null;}
while (p0 != null){
postOrder(t, p0);try {p0 = t.siblingAfter(p0);}catch (Exception e) {p0 = null;}
}System.out.print(p.element() + " ");
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
22
43
Metoda inorder 1/3
1
2 43
5 6 7
1098Metoda inorder - odwiedzane jest lewe skrajne poddrzewo, następnie korzeo drzewa, po czym następuje przejście przez pozostałe poddrzewa w kolejności od lewej do prawej strony.
Przechodzenie inorder: 2 1 8 5 9 3 10 6 7 4
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
44
Metoda inorder 2/3
static void inOrder(Tree t, Position p) {
Position p0 = p;
try {if (t.isExternal(p0))
System.out.print(p0.element() + " ");else {
try {p0 = t.firstChild(p0);inOrder(t, p0);
}catch (Exception e) {}
System.out.print(p.element() + " ");
try {p0 = t.siblingAfter(p0);}catch (Exception e) {p0 = null;}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie
2010-12-01
23
Metoda inorder 3/3
while (p0 != null) {inOrder(t, p0);try {p0 = t.siblingAfter(p0);}catch (Exception e) {p0 = null;}
}}
}catch (InvalidAccessorException e) {}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 45
Implementacja grafów
• Klasa IncidenceListGraph – dla każdego wierzchołka przechowywana jest lista wierzchołków przyległych (reprezentacja listowa)
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 46
A
C
B A B C
B A
C A
2010-12-01
24
Zastosowanie algorytmu Dijkstry
import jdsl.graph.api.*;import jdsl.graph.algo.IntegerDijkstraPathfinder;import jdsl.graph.ref.*;
public class Graph01 {
public static void main(String[] args) {
Graph gr = new IncidenceListGraph();
Vertex v[] = new Vertex[5];
//tworzenie i wstawianie wierzcholkow
for (int i = 0; i < v.length; i++) v[i] = gr.insertVertex(Integer.toString(i));
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 47
0
2
4
3
1
8010
10
10
10
40
20
20
20
30
...
//wstawianie krawędzi
gr.insertDirectedEdge(v[0],v[1],new Integer(80));gr.insertDirectedEdge(v[0],v[2],new Integer(40));gr.insertDirectedEdge(v[1],v[2],new Integer(10));gr.insertDirectedEdge(v[2],v[3],new Integer(20));gr.insertDirectedEdge(v[2],v[4],new Integer(10));gr.insertDirectedEdge(v[3],v[1],new Integer(10));gr.insertDirectedEdge(v[3],v[2],new Integer(30));gr.insertDirectedEdge(v[4],v[0],new Integer(10));gr.insertDirectedEdge(v[4],v[2],new Integer(20));gr.insertDirectedEdge(v[4],v[3],new Integer(20));
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 48
0
2
4
3
1
8010
10
10
10
40
20
20
20
30
2010-12-01
25
...
IntegerDijkstraPathfinder dist = new IntegerDijkstraPathfinder() {
protected int weight(Edge e) {
Integer i = (Integer) e.element();
return i.intValue();
}
};
dist.execute(gr,v[0],v[1]);
EdgeIterator ei = dist.reportPath();
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 49
0
2
4
3
1
8010
10
10
10
40
20
20
20
30
...
int sum = 0;
while(ei.hasNext()) {
Edge e = ei.nextEdge();
sum += ((Integer) e.element()).intValue();
System.out.println(gr.origin(e) + " --> " + gr.destination(e));
}
System.out.println(sum);
}
}
Paweł Lula, Katedra Systemów Obliczeniowych, Uniwersytet Ekonomiczny w Krakowie 50
0
2
4
3
1
8010
10
10
10
40
20
20
20
30