-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdag.py
125 lines (114 loc) · 3.36 KB
/
dag.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# -*- coding: utf-8 -*-
"""
Funkcije na grafih.
V ocenah časovne zahtevnosti je n število vozlišč v grafu,
m število povezav v grafu, d(u) pa število sosedov vozlišča u.
Pri tem predpostavljamo, da velja n = O(m)
(graf ima O(1) povezanih komponent).
Podane časovne zahtevnosti veljajo za predstavitev grafa s seznami sosedov.
"""
def topoloskaUreditev(G):
"""
Topološko urejanje usmerjenega acikličnega grafa z odstranjevanjem izvorov.
Časovna zahtevnost: O(m)
"""
stopnje = {u: 0 for u in G.vozlisca()}
for u in stopnje:
for v in G.izhodniSosedi(u):
stopnje[v] += 1
s = []
for u, d in stopnje.items():
if d == 0:
s.append(u)
topord = []
while len(s) > 0:
v = s.pop()
topord.append(v)
for u in G.izhodniSosedi(v):
stopnje[u] -= 1
if stopnje[u] == 0:
s.append(u)
if len(topord) < len(stopnje):
raise ValueError("Graf ima cikle!")
return topord
def najkrajsaPotDAG(G, s, t):
"""
Poišče najkrajšo pot od s do t v usmerjenem acikličnem grafu G.
Časovna zahtevnost: O(m)
"""
topord = topoloskaUreditev(G)
d = {u: None for u in G.vozlisca()}
p = {u: None for u in G.vozlisca()}
d[s] = 0
for i in range(topord.index(s), topord.index(t)):
u = topord[i]
l = d[u]
for v, r in G.utezeniIzhodniSosedi(u).items():
if d[v] is None or d[v] > l+r:
d[v] = l+r
p[v] = u
pot = []
u = t
while u is not None:
pot.append(u)
u = p[u]
return (d[t], list(reversed(pot)))
def najdaljsaPotDAG(G, s, t):
"""
Poišče najdaljšo pot od s do t v usmerjenem acikličnem grafu G.
Časovna zahtevnost: O(m)
"""
topord = topoloskaUreditev(G)
d = {u: None for u in G.vozlisca()}
p = {u: None for u in G.vozlisca()}
d[s] = 0
for i in range(topord.index(s), topord.index(t)):
u = topord[i]
l = d[u]
for v, r in G.utezeniIzhodniSosedi(u).items():
if d[v] is None or d[v] < l+r:
d[v] = l+r
p[v] = u
pot = []
u = t
while u is not None:
pot.append(u)
u = p[u]
return (d[t], list(reversed(pot)))
def steviloPoti(G, s, t):
"""
Za usmerjen acikličen graf G z utežmi,
ki predstavljajo število načinov, kako lahko sledimo povezavi,
določi število načinov, kako lahko pridemo od vozlišča s do vozlišča t.
Časovna zahtevnost: O(m)
"""
st = {u: 1 if u == s else 0 for u in G.vozlisca()}
for u in topoloskaUreditev(G):
for v, d in G.utezeniIzhodniSosedi(u).items():
st[v] += st[u] * d
return st[t]
def vecTopoUreditev(G):
"""
Ugotovi, ali ima usmerjen acikličen graf več kot eno topološko ureditev.
Časovna zahtevnost: O(m)
"""
stopnje = {u: 0 for u in G.vozlisca()}
for u in stopnje:
for v in G.izhodniSosedi(u):
stopnje[v] += 1
s = []
for u, d in stopnje.items():
if d == 0:
s.append(u)
out = False
n = len(G)
for i in range(n):
if len(s) == i:
return False
if len(s) > i+1:
out = True
for u in G.izhodniSosedi(s[i]):
stopnje[u] -= 1
if stopnje[u] == 0:
s.append(u)
return out