Zadanie 1 - otwartaszkola.edu.pl

advertisement
VB - algorytmy
Zadanie4_4
autor: Janusz Białowąs
90 min
Szukanie minimalnego drzewa rozpinającego – algorytm Prima
OPIS ZADANIA
Algorytm Prima to zadanie polegające na utworzeniu prostej aplikacji szukającej minimalnego drzewa
rozpinającego dla grafu ważonego wprowadzonego z pliku tekstowego. Celem zadania jest rozwiązanie jednego
z podstawowych problemów algorytmicznych teorii grafów, wykorzystując algorytm Prima.
EFEKT KOŃCOWY
Efektem końcowym zadania jest aplikacja przedstawiona na ilustracji poniżej. Pokazuje ona listy sąsiedztwa
grafu wprowadzonego z pliku tekstowego oraz minimalne drzewo rozpinające dla niego wraz z jego kosztem.
- Aby wykonać zadanie, niezbędne jest wykorzystanie plików graf.txt, graf1.txt. graf2.txt
REALIZACJA ZADANIA
Wykonując to zadanie, dowiesz się, jak odszukać minimalne drzewo rozpinające grafu za pomocą algorytmu
Prima. Wykorzystasz struktury danych ArrayList oraz Structure do przechowywania danych. Podczas realizacji
zadania skoncentruj się na implementacji algorytmu oraz wykorzystanych strukturach danych.
Uwaga: W kolejnych krokach scenariusza nowo dodany kod oznaczony został czcionką pogrubioną.
Niepogrubione linie kodu mają służyć wyłącznie do oznaczenia miejsca, w którym należy wpisać nowy kod.
Algorytmika i programowanie
1
VB - algorytmy
autor: Janusz Białowąs
Krok 1: Tworzenie projektu aplikacji i formularza
1. Utwórz nowy projekt aplikacji Windows o nazwie Grafy-Prim w folderze wskazanym przez nauczyciela.
2. Ustaw następujące właściwości formularza.
Właściwość
Wartość
Text
Minimalne drzewo rozpinające - algorytm Prima
3. Wstaw do formularza dwa pola tekstowe TextBox., dwie etykiety Label oraz dwa przyciski Button. Dla
pól TextBox ustaw wartości właściwości MultiLine oraz ReadOnly na True. Ustaw właściwości Name i
Text wstawionych formantów według tabeli poniżej.
Typ kontrolki
Name
Text
Label
Label1
Koszt drzewa
Label
lblKosztDrzewa
TextBox
txtListy_s
TextBox
txtDrzewoMinimalne
Button
btnDrzewoSzukaj
Szukaj minimalnego drzewa rozpinającego
Button
btnKoniec
Wyjście
4. Ustaw dla pól typu TexBox właściwość ScrollBars na Both.
5. Rozmieść kontrolki podobnie jak na rysunku powyżej, pamiętając, że kontrolka txtListy_s znajduje się
po lewej stronie formularza.
6. Skopiuj do folderu rozwiązania plik graf.txt, graf1.txt, graf2.txt z lokalizacji wskazanej przez
nauczyciela.
Krok 2: Deklaracja zmiennych globalnych w aplikacji
1. Przejdź do edytora kodu (F7) i zadeklaruj tablicę Listy_s typu ArrayList przechowującą listy sąsiedztwa
grafu.
Public Class form1
Inherits System.Windows.Forms.Form
Dim Listy_s() As ArrayList
2. Zadeklaruj i zainicjuj obiekt o nazwie kopiec typu ArrayList, służący do przechowywania krawędzi,
wśród których będziemy szukać najtańszej.
Inherits System.Windows.Forms.Form
Dim Listy_s() As ArrayList
Dim kopiec As New ArrayList()
3. Zadeklaruj tablicę odwiedzone o zerowym rozmiarze typu Boolean, służącą do odznaczania
wierzchołków, które zostały już odwiedzone („zrobione”).
Dim Listy_s() As ArrayList
Dim kopiec As New ArrayList()
Dim odwiedzone() As Boolean
Algorytmika i programowanie
2
VB - algorytmy
autor: Janusz Białowąs
4. Zadeklaruj i zainicjuj obiekt drzewo_minialne typu ArrayList, służący do zapamiętania minimalnego
drzewa rozpinającego grafu.
Dim kopiec As New ArrayList()
Dim odwiedzone() As Boolean
Dim drzewo_minimalne As New ArrayList()
5. Zadeklaruj zmienną IleWierzcholkow, typu Integer służącą do zapamiętania informacji o ilości
wierzchołków w grafie.
Dim odwiedzone() As Boolean
Dim drzewo_minimalne As New ArrayList()
Dim ileWierzcholkow As Integer
6. Zadeklaruj zmienną w typu krawedz_g (typ krawedz_g jest strukturą, która będzie utworzona w dalszej
części programu).
Dim drzewo_minimalne As New ArrayList()
Dim ileWierzcholkow As Integer
Dim w As krawedz_g
7. Zadeklaruj stałą o nazwie plik, przechowującą informacje o lokalizacji i nazwie pliku tekstowego
zawierającego opis grafu (lokalizacja wskazana w stałej odwołuje się do folderu rozwiązania).
Dim ileWierzcholkow As Integer
Dim w As krawedz_g
Const plik As String = "../graf.txt"
Krok 3: Utworzenie struktur do przechowywania danych o grafie
1. Zadeklaruj strukturę o nazwie krawedz_g.
Private Structure krawedz_g
End Structure
2. Zadeklaruj wewnątrz struktury pola, które będą ją tworzyły.
Private Structure krawedz_g
Dim wierzcholek As Integer
Dim koszt_k As Integer
3. Zadeklaruj strukturę o nazwie e_kopca.
Private Structure e_kopca
End Structure
4. Zadeklaruj wewnątrz struktury pola, które będą ją tworzyły.
Private Structure e_kopca
Dim w_a As Integer
Dim w_b As Integer
Dim koszt_k As Integer
Algorytmika i programowanie
3
VB - algorytmy
autor: Janusz Białowąs
Krok 4: Dodanie procedur odczytujących opis grafu z pliku tekstowego
1. Utwórz procedurę o nazwie odczyt_z_pliku.
Sub odczyt_z_pliku()
End Sub
2. Zadeklaruj zmienne potrzebne w procedurze.
Sub
Dim
Dim
Dim
Dim
Dim
odczyt_z_pliku()
nrPliku As Integer
wierzcholki() As String
wiersz As String
i, j As Integer
temp As krawedz_g
3. Otwórz blok kodu chronionego pozwalający na obsługę błędów, mogących wystąpić przy odczycie
danych z pliku.
Dim w1, w2 As Integer
Dim temp As krawedz_g
Try
4. Otwórz plik tekstowy, którego nazwa jest zapamiętana pod stałą o nazwie plik.
Dim w1, w2 As Integer
Dim temp As krawedz_g
Try
nrPliku = FreeFile()
FileOpen(nrPliku, plik, OpenMode.Input)
5. Odczytaj z pliku liczbę wierzchołków i zmień rozmiar tablicy o nazwie Listy_s według tej wartości.
nrPliku = FreeFile()
FileOpen(nrPliku, plik, OpenMode.Input)
ileWierzcholkow = LineInput(nrPliku)
ReDim Listy_s(ileWierzcholkow)
6. Zainicjuj elementy tablicy Listy_s.
ileWierzcholkow = LineInput(nrPliku)
ReDim Listy_s(ileWierzcholkow)
For i = 1 To ileWierzcholkow
Listy_s(i) = New ArrayList()
Next
7. Utwórz listy sąsiedztwa grafu, wczytując kolejne wiersze pliku tekstowego zawierające opis krawędzi i jej
koszt. Wykorzystaj do zapamiętania sąsiedniego wierzchołka oraz kosztu krawędzi strukturę
krawedz_g.
Listy_s(i) = New ArrayList()
Next
Algorytmika i programowanie
4
VB - algorytmy
autor: Janusz Białowąs
Do While Not EOF(nrPliku)
wiersz = LineInput(nrPliku)
wierzcholki = wiersz.Split(" ", Chr(13))
w.wierzcholek = wierzcholki(1)
w.koszt_k = wierzcholki(2)
Listy_s(CInt(wierzcholki(0))).Add(w)
w.wierzcholek = wierzcholki(0)
w.koszt_k = wierzcholki(2)
Listy_s(CInt(wierzcholki(1))).Add(w)
Loop
8. Zamknij plik tekstowy oraz wyczyść i uaktywnij pole txtListy_s.
Listy_s(CInt(wierzcholki(1))).Add(w)
Loop
FileClose(nrPliku)
txtListy_s.Clear()
txtListy_s.Visible = True
9. Wyświetl w polu tekstowym listy sąsiedztwa grafu wraz z kosztami krawędzi.
txtListy_s.Clear()
txtListy_s.Visible = True
For i = 1 To ileWierzcholkow
txtListy_s.Text = txtListy_s.Text & " wierzchołek (" & i & ") = "
j = 0
Do While Listy_s(i).Count > j
temp = Listy_s(i).Item(j)
txtListy_s.Text = txtListy_s.Text & temp.wierzcholek & "(" & temp.koszt_k
& ") "
j += 1
Loop
txtListy_s.Text = txtListy_s.Text & vbCrLf
Next
10. Obsłuż typowe błędy mogące wystąpić podczas odczytu danych z pliku i zakończ blok kodu
chronionego poleceniem End Try.
txtListy_s.Text = txtListy_s.Text & vbCrLf
Next
Catch ex As Exception
MessageBox.Show("Błąd odczytu z pliku", "Błąd", MessageBoxButtons.OK,
MessageBoxIcon.Error)
btnDrzewoSzukaj.Enabled = False
txtListy_s.Text = "Błąd odczytu z pliku"
End Try
11. Utwórz procedurę obsługi zdarzenia Load formularza: z listy rozwijalnej Class Name wybierz opcję
(Base Class Events), zaś z listy Method Name wybierz zdarzenie Load.
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
End Sub
Algorytmika i programowanie
5
VB - algorytmy
autor: Janusz Białowąs
12. Wywołaj procedurę odczyt_z_pliku oraz ustaw właściwość TabIndex przycisku btnDrzewoSzukaj
na 0.
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
odczyt_z_pliku()
btnDrzewoSzukaj.TabIndex = 0
Krok 5: Tworzenie procedury tworzącej kopiec krawędzi sąsiadujących z odwiedzonymi już
wierzchołkami.
1. Przejdź do edytora kodu i utwórz procedurę o nazwie na_kopiec z jednym parametrem przekazywanym
przez wartość.
Sub na_kopiec(ByVal nr_wezla As Integer)
End Sub
2. Zadeklaruj zmienne potrzebne w procedurze.
Sub na_kopiec(ByVal nr_wezla As Integer)
Dim j As Integer = 0
Dim element As e_kopca
3. Dołącz do kopca wszystkie elementy listy sąsiedztwa wskazanego w parametrze wierzchołka.
Dim j As Integer = 0
Dim element As e_kopca
For j = 0 To Listy_s(nr_wezla).Count - 1
element.w_a = nr_wezla
w = Listy_s(nr_wezla).Item(j)
element.w_b = w.wierzcholek
element.koszt_k = w.koszt_k
kopiec.Add(element)
Next
Krok 6: Tworzenie procedury szukającej najtańszej krawędzi w kopcu
1. Przejdź do edytora kodu i utwórz procedurę o nazwie szukaj_krawedzi z jednym parametrem
przekazywanym przez referencję.
Sub szukaj_krawedzi(ByRef wezel As Integer)
End Sub
2. Zadeklaruj zmienne potrzebne w procedurze.
Sub
Dim
Dim
Dim
Dim
Dim
szukaj_krawedzi(ByRef wezel As Integer)
element As New e_kopca()
min_koszt As Integer = 0
w1, w2 As Integer
j, indeks As Integer
wpis As Boolean = True
Algorytmika i programowanie
6
VB - algorytmy
autor: Janusz Białowąs
3. Rozpocznij pętlę Do…Loop, która wykona dodanie nowego elementu do minimalnego drzewa
rozpinającego.
Dim j, indeks As Integer
Dim wpis As Boolean = True
Do
4. Wybierz pierwszy element kopca jako krawędź o minimalnym koszcie.
Dim wpis As Boolean = True
Do
element = kopiec.Item(0)
min_koszt = element.koszt_k
w1 = element.w_a
w2 = element.w_b
5. Wyszukaj najtańszą krawędź na kopcu, wykorzystując algorytm szukania minimum w zbiorze.
w1 = element.w_a
w2 = element.w_b
For j = 1 To kopiec.Count - 1
element = kopiec.Item(j)
If element.koszt_k < min_koszt Then
min_koszt = element.koszt_k
w1 = element.w_a
w2 = element.w_b
indeks = j
End If
Next
6. Sprawdź, czy wyszukana krawędź nie tworzy cyklu w wyszukanym drzewie minimalnym (cykl wystąpi,
gdy obydwa wierzchołki krawędzi były już odwiedzione).
End If
Next
If Not (odwiedzone(w1) And odwiedzone(w2)) Then
7. Zaznacz kolejny wierzchołek jako odwiedzony i dodaj wyszukaną minimalną krawędź do drzewa
minimalnego.
Next
If Not (odwiedzone(w1) And odwiedzone(w2)) Then rtbTekst.Cut()
If Not odwiedzone(w1) Then
odwiedzone(w1) = True
wezel = w1
End If
If Not odwiedzone(w2) Then
odwiedzone(w2) = True
wezel = w2
End If
drzewo_minimalne.Add(kopiec.Item(indeks))
wpis = False
End If
Algorytmika i programowanie
7
VB - algorytmy
autor: Janusz Białowąs
8. Usuń wyszukaną krawędź z kopca i zakończ pętlę Do…Loop, gdy został dokonany wpis kolejnej
krawędzi tworzącej minimalne drzewo rozpinające.
wpis = False
End If
kopiec.RemoveAt(indeks)
Loop While wpis
Krok 8: Tworzenie funkcji sprawdzającej czy wszystkie wierzchołki zostały odwiedzone
(„zrobione”)
1. Przejdź do edytora kodu i utwórz funkcję o nazwie czy_wszystkie zwracającą wartość typu Boolean.
Function czy_wszystkie() As Boolean
End Function
2. Zadeklaruj zmienne potrzebne w procedurze.
Function czy_wszystkie() As Boolean
Dim i As Integer = 1
3. Sprawdź kolejne wierzchołki, czy są ”zrobione”; jeżeli któryś nie był jeszcze odwiedzony, przerwij
działania funkcji i zwróć wartość False.
Function czy_wszystkie() As Boolean
Dim i As Integer = 1
Do
If Not odwiedzone(i) Then Return False
i += 1
Loop Until i > ileWierzcholkow
4. Jeżeli wszystkie wierzchołki grafu zostały „zrobione”, zakończ działanie funkcji i zwróć wartość True.
i += 1
Loop Until i > ileWierzcholkow
Return True
Krok 9: Tworzenie procedury szukającej minimalnego drzewa rozpinającego grafu.
1. W widoku projektu kliknij dwukrotnie przycisk btnDrzewoSzukaj, aby przejść do edytora kodu i
procedury obsługi zdarzenia kliknięcia tej kontrolki.
Private Sub btnDrzewoSzukaj_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnDrzewoSzukaj.Click
End Sub
2. Zadeklaruj zmienne lokalne w procedurze.
Private Sub btnDrzewoSzukaj_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnDrzewoSzukaj.Click
Dim wezel As Integer = 1
Algorytmika i programowanie
8
VB - algorytmy
autor: Janusz Białowąs
Dim i As Integer
Dim element As e_kopca
Dim Koszt As Integer = 0
3. Zmień rozmiar tablicy o nazwie odwiedzone.
Dim element As e_kopca
Dim Koszt As Integer = 0
ReDim odwiedzone(ileWierzcholkow)
4. Zaznacz wszystkie wierzchołki grafu jako jeszcze nieodwiedzone (False).
Dim Koszt As Integer = 0
ReDim odwiedzone(ileWierzcholkow)
For i = 1 To ileWierzcholkow
odwiedzone(i) = False
Next
5. Wyczyść kontrolki txtDrzewoMinimalne oraz lblKosztDrzewa oraz wyzeruj zmienną przechowującą
koszt drzewa minimalnego.
odwiedzone(i) = False
Next
txtDrzewoMinimalne.Clear()
lblKosztDrzewa.Text = ""
Koszt = 0
6. Odwiedź pierwszy wierzchołek i odznacz to w tablicy o nazwie odwiedzone.
lblKosztDrzewa.Text = ""
Koszt = 0
odwiedzone(1) = True
7. Rozpocznij pętlę Do…Loop, w której wywoływane są procedury tworzące kopiec oraz szukające
najtańszej krawędzi.
Koszt = 0
odwiedzone(1) = True
Do
na_kopiec(wezel)
szukaj_krawedzi(wezel
8. Zakończ działanie pętli, gdy wszystkie wierzchołki zostaną odwiedzone.
na_kopiec(wezel)
szukaj_krawedzi(wezel
Loop Until czy_wszystkie()
9. Wyświetl minimalne drzewo rozpinające oraz jego koszt w odpowiednich kontrolkach.
na_kopiec(wezel)
szukaj_krawedzi(wezel
Loop Until czy_wszystkie()
For i = 0 To drzewo_minimalne.Count - 1
Algorytmika i programowanie
9
VB - algorytmy
autor: Janusz Białowąs
element = drzewo_minimalne.Item(i)
txtDrzewoMinimalne.Text = txtDrzewoMinimalne.Text & element.w_a & " " &
element.w_b & " (" & element.koszt_k & ")" & vbCrLf
Koszt += element.koszt_k
Next
lblKosztDrzewa.Text = CInt(Koszt)
Krok 10: Tworzenie procedury kończącej pracę programu
1. W widoku projektu kliknij dwukrotnie przycisk Wyjście, aby przejść do edytora kodu i procedury obsługi
zdarzenia kliknięcia tej kontrolki.
Private Sub btnKoniec_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnKoniec.Click
End Sub
2. Zadeklaruj zmienną pytanie typu DialogResult.
Private Sub btnKoniec_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnKoniec.Click
Dim pytanie As DialogResult
3. Wykorzystując metodę MessageBox.Show, zadaj pytanie użytkownikowi, czy chce zakończyć pracę
aplikacji..
Private Sub btnKoniec_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnKoniec.Click
Dim pytanie As DialogResult
pytanie = MessageBox.Show("Czy chcesz zakończyć pracę aplikacji?", "Wyjście",
MessageBoxButtons.YesNo, MessageBoxIcon.Question,
MessageBoxDefaultButton.Button2)
4. Jeśli uzyskałeś pozytywną odpowiedź, zakończ pracę aplikacji.
Dim pytanie As DialogResult
pytanie = MessageBox.Show("Czy chcesz zakończyć pracę programu?", "Wyjście",
MessageBoxButtons.YesNo, MessageBoxIcon.Question,
MessageBoxDefaultButton.Button2)
If pytanie = DialogResult.Yes Then
Close()
End If
Krok 11: Testowanie aplikacji
1. Uruchom aplikację.
2. Sprawdź, jak program wyszukuje minimalne drzewo rozpinające.
3. Sprawdź działanie aplikacji dla grafów zapisanych w plikach graf1.txt i graf2.txt.
4. Zapisz dowolny graf ważony w pliku tekstowym i przetestuj działanie programu dla tego grafu.
Algorytmika i programowanie
10
Download