Zapisz jako PDF

Transkrypt

Zapisz jako PDF
Spis treści
1 Krótki wstęp do teorii grafów
1.1 Graf
1.2 Definicja matematyczna
1.3 Krawędzie skierowane i nieskierowane
1.3.1 Sąsiedztwo
1.3.2 Stopień wierzchołka
1.3.3 Stopień wejściowy
1.3.4 Stopień wyjściowy
1.4 Ścieżka
1.4.1 Ścieżka prosta
1.4.2 Osiągalność
1.5 Cykl
1.5.1 W grafie skierowanym
1.5.1.1 Prosty
1.5.2 W grafie nieskierowanym
1.6 Graf spójny
1.7 Graf pełny
1.8 Graf dwudzielny
1.9 Graf acykliczny
1.10 Graf wolny
1.11 Jak skonstruować graf skierowany z nieskierowanego i odwrotnie
1.12 Zastosowania
1.13 Zadania
1.13.1 Zadanie 1
1.13.2 Zadanie 2
1.13.3 Zadanie 3
1.13.4 Zadanie 4
1.13.5 Zadanie 5
2 Moduł przedstawiający reprezentację abstrakcyjnego grafu
2.1 Zadania
3 Algorytm szukający najkrótszej ścieżki
3.1 Zadania
Krótki wstęp do teorii grafów
Graf
Graf jest to zbiór wierzchołków i zbiór krawędzi . Każdy wierzchołek
to po prostu jakiś
obiekt, najczęściej po prostu etykieta. Natomiast każda krawędz
to para wierzchołków, czyli
. Istnienie krawędzi oznacza istnienie relacji pomiędzy tymi dwoma wierzchołkami.
Jedna krawędź nie może związać ze sobą więcej niż dwóch wierzchołków. Dwa wierzchołki mogą być
ze sobą związane więcej niż jedną krawędzią.
Definicja matematyczna
Grafem nazywamy parę uporządkowaną
przy czym:
— zbiór wierzchołków grafu,
— zbiór krawędzi grafu, każde
to para elementów
,
.
Krawędzie skierowane i nieskierowane
Są dwa typy grafów:
graf nieskierowany, w którym krawędzie nie mają kierunku, czyli krawędź
jest
tym samym co krawędź
. Przykładem takiego grafu może być graf osób gdzie
krawędzie reprezentują spotkania. Ponieważ jeśli A. spotkał B., to i B. spotkał A., więc graf jest
nieskierowany.
graf skierowany, w którym rozróżniamy krawedź
i
. Przykładem takiego grafu
może być graf osób i tego czy się lubią — jeśli A. lubi B., to B. może też lubić A., ale niestety
nie musi.
Jeśli
jest krawędzią w grafie skierowanym, to mówimy, że krawędź wychodzi z wierzchołka
i wchodzi do wierzchołka .
Sąsiedztwo
Jeżeli
jest krawędzią grafu, to mówimy, że wierzchołek
jest sąsiadem wierzchołka .
Jeżeli graf jest nieskierowany, relacja sąsiedztwa jest symetryczna. Jeżeli graf jest skierowany,
relacja sąsiedztwa nie musi być symetryczna. W grafie skierowanym, jeżeli jest wierzchołkiem
sąsiadującym z , relacja ta jest często zapisywana jako
.
Stopień wierzchołka
Stopniem wierzchołka jest liczba krawędzi wychodzących lub wchodzących do tego wierzchołka. W
przypadku grafu nieskierowanego, kierunek nie ma znaczenia, więc jest to po prostu liczba krawędzi
łączących dany wierzchołek z innymi.
Stopień wejściowy
W grafie skierowanym — liczba krawędzi wchodzących do wierzchołka.
Stopień wyjściowy
W grafie skierowanym — liczba krawędzi wychodzących z wierzchołka.
Oczywiście stopień wejściowy plus stopień wyjściowy muszą w sumie dać stopień wierzchołka.
Ścieżka
Ścieżka (droga) długości
z wierzchołka
do wierzchołka
wierzchołków
, takich że
krawędzi dla wszystkich od 1 do .
Długość ścieżki jest liczbą krawędzi w ścieżce.
i
w grafie
, a pary
jest ciagiem
należą do zbioru
Ścieżka zawiera wierzchołki
,
,…,
i krawędzie
,
,…,
.
Ścieżka prosta
Ścieżka, której wszystkie wierzchołki są różne.
Osiągalność
W grafie
istnieje ścieżka
z
o wierzchołku
do .
możemy powiedzieć, że jest osiągalny z wierzchołka
, jeżeli
Cykl
W grafie skierowanym
W grafie skierowanym
ścieżka
zawiera co najmniej jedną krawędź.
tworzy cykl, jeżeli
i ścieżka
Pętla jest cyklem o długości jeden.
Prosty
Cykl jest prosty jeżeli
są różne.
W grafie nieskierowanym
W grafie nieskierowanym
są różne i
ścieżka
tworzy cykl, jeżeli
,
.
Graf spójny
Graf nieskierowany jest spójny, jeżeli każda para wierzchołków jest połączona ścieżką.
Graf skierowany jest silnie spójny, jeżeli każde dwa wierzchołki są osiągalne jeden z drugiego.
Graf pełny
Graf nieskierowany, w którym każda para wierzchołków połączona jest krawędzią.
Graf dwudzielny
Graf nieskierowany, którego zbiór wierzchołków można podzielić na dwa rozłączne zbiory tak, że
krawędzie nie łączą wierzchołków tego samego zbioru.
Pojęcie to można uogólnić na trzy i więcej zbiorów.
Graf acykliczny
Graf niezawierający cykli.
Graf wolny
Acykliczny graf nieskierowany.
Jak skonstruować graf skierowany z nieskierowanego i odwrotnie
W przypadku grafu nieskierowanego, każdą jego krawędź nieskierowaną
skierowane gałęzie
i
zamieniamy na dwie
.
Konstruując wersję nieskierowaną grafu skierowanego, usuwamy wszystkie pętle i zamieniamy
wszystkie skierowane krawędzie na nieskierowane.
Zastosowania
Grafy ze względu na swoją ogólność są jednymi z najbardziej powszechnych modeli różnych strukur
— zarówno tych stworzonych przez człowieka, jak i tych stworzonych przez naturę. Używa się ich do
modelowania związków a także procesów dynamicznych w systemach fizycznych, biologicznych i
społecznych, ale także i w ligwistyce.
Zadania
Zadanie 1
Który z przedstawionych grafów na rysunkach Figure 1, Figure 2, Figure 3, Figure 4, Figure 5,
Figure 6 jest grafem wolnym?
Jakie są cechy grafu wolnego?
Zadanie 2
Który z przedstawionych grafów Figure 1, Figure 2, Figure 3, Figure 4, Figure 5, Figure 6 jest
grafem pełnym?
Jakie są cechy grafu pełnego?
Zadanie 3
Wypisz sąsiadów wierzchołka(ów) o najwyższym stopniu w grafach na rysunkach Figure 1, Figure 2,
Figure 3, Figure 4, Figure 5, Figure 6.
Zadanie 4
Dla grafu na rysunku Figure 1:
Wypisz jakie wierzchołki są nieosiągalne dla wierzchołków 3 i 7.
Które wierzchołki nie mają żadnego osiągalnego wierdzchołka?
Jaka jest największa możliwa długość ścieżki?
Dla grafu na rysunku Figure 5:
Czy graf ma wierzchołek, dla którego wszystkie inne wierzchołki są osiągalne?
Czy graf ma wierzchołek, który nie ma żadnego osiągalnego wierzchołka?
Dla grafu na rysunku Figure 6
Wypisz najdłuższą możliwą ścieżkę.
Zadanie 5
Które z grafów przedstawionych na rysunkach Figure 1, Figure 2, Figure 3, Figure 4, Figure 5,
Figure 6 zawierają cykle?
Moduł przedstawiający reprezentację abstrakcyjnego grafu
Poniższy tekst programu jest autorstwa Niko Wilberta.
#!/usr/bin/env python
# -*- coding: utf-8 -*"""
This module contains all elements for an abstract graph representation.
Written by Niko Wilbert for the G-Node Python Winter School 2010.
"""
class Node(object):
"""Base class for nodes.
To add additional data attributes to nodes you can derive subclasses.
"""
def __init__(self):
"""Initialize the node."""
self._out_edges = [] # outgoing edges
self._in_edges = [] # incoming edges
@property
def out_edges(self):
return self._out_edges
class Edge(object):
"""Edge class.
This class also registers itself with the affected nodes, so it sits
between Node and Graph in the hierarchy. The head and tail can also be
None.
"""
def __init__(self, head, tail):
"""Initialize the edge.
head, tail -- The end and starting node of this edge, or can be None.
"""
self._head = head
if head is not None:
head._in_edges.append(self)
self._tail = tail
if tail is not None:
tail._out_edges.append(self)
def _set_head(self, head):
"""Set the head and register this in the nodes as well.
The head can also be None, then the edge is unregistered.
"""
if self._head is not None:
self._head._in_edges.remove(self)
self._head = head
if head is not None:
self._head._in_edges.append(self)
def _set_tail(self, tail):
"""Set the tail and register this in the nodes as well.
The tail can also be None, then the edge is unregistered.
"""
if self._tail is not None:
self._tail._out_edges.remove(self)
self._tail = tail
if tail is not None:
self._tail._out_edges.append(self)
# use these public properties
head = property(lambda self: self._head, _set_head)
tail = property(lambda self: self._tail, _set_tail)
def clear_nodes(self):
"""Clear the node references."""
self._set_tail(None)
self._set_head(None)
class GraphException(Exception):
"""Base Exception for Graph."""
pass
class NoPathGraphException(GraphException):
"""Exception signaling that there is no path between nodes."""
pass
class Graph(object):
"""Class to represent a complete graph with nodes and edges.
Note that this class does not support nodes which do not belong to any
edge (internally only edges are stored).
"""
def __init__(self, edges=None):
self._edges = set()
if edges:
for edge in edges:
self.add_edge(edge)
@property
def edges(self):
"""Return list of the edges in this graph."""
return self._edges
@property
def nodes(self):
"""Return set of nodes in this graph."""
nodes = set()
for edge in self._edges:
nodes.add(edge.head)
nodes.add(edge.tail)
return nodes
def add_edge(self, edge):
"""Add an edge to the graph."""
self._edges.add(edge)
def remove_edge(self, edge):
"""Remove an edge from the graph."""
edge.clear_nodes()
self._edges.remove(edge)
Zadania
Zadania są autorstwa Niko Wilberta i Bartosza Teleńczuka.
Powyżej przedstawiona jest implementacja klas reprezentujących obiekt. Na kartce dokonaj analizy
kodu.
1. Wypisz wszystkie nazwy klas, ich metody i własności publiczne (czyli te, które nie zaczynają się
od podkreślenia). Spróbuj zrozumieć jakie jest ich wszystkich działanie (przeczytaj docstringi!).
Nie zawahaj się zapytać ćwiczeniowca, jeżeli masz jakieś wątpliwości. Znajdź ewentualne
błędy implementacji. Jeżeli składnia @property jest dla Ciebie dziwna lub niezrozumiała,
przeczytaj o dekoratorach i property.
2. Zastanów się, jak poszczególne klasy są ze sobą związane (dziedziczenie kontra wykorzystanie
explicite cudzych metod). Narysuj prosty diagram.
3. Korzystając z klasy Graph zaimplementuj graf przedstawiony na rysunku Figure 5 (nr
wierzchołka zmień na nazwę np. 1 na N1) i Figure 7.
Algorytm szukający najkrótszej ścieżki
Autor Niko Wilbert
Krótkie wprowadzenie do problemu poszukiwania najkrótszej ścieżki można znaleźć tu
#!/usr/bin/env python
#coding=utf-8
from heapq import heappop, heappush
def shortest_path(start_node, end_node, weight_func=lambda edge: 1):
"""Return the shortest path and its overall weight.
weight_func -- Functions that maps an edge to a weight value, the
default function maps all edges to 1.
"""
## this is basically Dijkstra's algorithm
# store the shortest path to all nodes,
# the value tuples contain the path length and the previous node
shortest_paths = {start_node: (, None)}
# we use this list as a priority cue with heapq
# the tuples contain the overall path length and the edge itself
edge_heap = []
for edge in start_node.out_edges:
heappush(edge_heap, (weight_func(edge), edge))
while edge_heap:
path_weight, edge = heappop(edge_heap)
if ((edge.head not in shortest_paths) or
(shortest_paths[edge.head][] > path_weight)):
shortest_paths[edge.head] = (path_weight, edge)
# if we already visited this node then there may be edge
# duplicates in the heap, but this is no problem because
# the newer edges are guaranteed to come first
for out_edge in edge.head.out_edges:
heappush(edge_heap, (path_weight + weight_func(out_edge),
out_edge))
if end_node not in shortest_paths:
err = ("The is no connection from node %s" % str(start_node) +
" to node %s." % str(end_node))
raise NoPathGraphException(err)
# assemble the shortest path from end to start
path_weight = shortest_paths[end_node][]
path_edges = [shortest_paths[end_node][1]]
current_node = path_edges[-1].tail
while current_node is not start_node:
path_edges.append(shortest_paths[current_node][1])
current_node = path_edges[-1].tail
return path_edges[::-1], path_weight
Zadania
Korzystając z kodu klasy Graph oraz shortest_path() napisz aplikację do planowania podróży. W
tej aplikacji poszczególne miasta bedą reprezentowane jako węzły w grafie, a krawędzie pomiędzy
węzłami będą reprezentowały możliwe środki komunikacji.
1. Napisz klasę CityNode, która roszerza klasę Node o nazwę (miasta), która definiowana jest
przy inicjalizacji klasy.
2. Napisz klasę TransportationEdge rozszerzającą klasę Edge. Krawędzie powinny być
skierowane i obarczone dwoma rodzajami wag — czasem podróży i kosztem; klasa powinna też
zawierać pole description zawierające krótki opis środka transportu.
3. Zaimplementuj graf pokazany na rysunku Figure 8. Zastanów się pierw jakie operacje powinny
być udostępnione przez ten graf, jakie może być jego zastosowanie.
4. Chciałbyś znaleźć najkrótszą drogę pomiędzy Berlinem a Kolonią. Funkcja shortest_path()
znajduje najkrótszą drogę w grafie. Korzystając z tej funkcji rozszerz klasę Graph o metody
poszukujące najkrótszej i najtańszej drogi.
5. Znajdź najkrótszą drogę między Berlinem a Kolonią.

Podobne dokumenty