GRAPH
COURSE OUTLINE
Basic Graph (review) Shortest Path
Minimum Spanning Tree
BASIC GRAPH
DEFINITION
G = (V, E)
MORE DEFINITIONS
weighted vs unweighted directed vs undirected
IMPLEMENTATION
UNDIRECTED GRAPH
vector< int > v[ N ] ; // an edge between a and b v[ a ].push_back( b ) ; v[ b ].push_back( a ) ;
DIRECTED GRAPH
vector< int > v[ N ] ; // an edge from a to b v[ a ].push_back( b ) ;
UNWEIGHTED GRAPH
vector< int > v[ N ] ; // an edge between a and b v[ a ].push_back( b ) ; v[ b ].push_back( a ) ;
WEIGHTED GRAPH
typedef pair< int , int > ii ; vector< ii > v[ N ] ;
// an edge between a and b with weight w v[ a ].push_back( ii( b , w ) ) ;
v[ b ].push_back( ii( a , w ) ) ; // v[ a ].emplace_back( b , w ) ; // v[ b ].emplace_back( a , w ) ;
TRAVERSING NEIGHBOR
vector< int > v[ N ] ;
// go through all vertices adjacent to a for ( int x : v[ a ] ) {
// x: a vertice directly linked to by "a"
}
typedef pair< int , int > ii ; vector< ii > v[ N ] ;
// go through all vertices adjacent to a for ( ii x : v[ a ] ) {
int b = x.first , w = x.second
// b: a vertice directly linked to by "a"
// w: weight(a, b) }
SHORTEST PATH
PATH
A path on a graph is a sequence of vertices
satisfying ( )
G = (V, E) , , , … , , ∈ V v
1v
2v
3v
n−1v
n( , v
iv
i+1) ∈ E 1 ≤ i < n
WEIGHT OF A PATH
The weight of a path is the sum
, , , … , , ∈ V v
1v
2v
3v
n−1v
nweight( , )
∑
n−1i=1v
iv
i+1SHORTEST PATH
The shortest path from to is the path with minimum weight among all paths
satisfying and
a b v
1, , , … , v
2v
3v
n−1, v
n= a
v
1v
n= b
HOW TO FIND THE SHORTEST PATH
SHORTEST PATH ON UNWEIGHTED GRAPH
Breadth-First Search (BFS) Time:
O(V + E)
0-1 BFS
Implement with a deque Time:
O(V + E)
SHORTEST PATH ON WEIGHTED GRAPH
Floyd-Warshall Algorithm (All-pairs) Dijkstra's Algorithm (Single-source)
Bellman-Ford Algorithm (Single-source)
NEGATIVE EDGE
vs
NEGATIVE CYCLE
FLOYD-WARSHALL
No negative cycle
Dynamic Programming
// dis[ i ][ j ]: initialized to weight of edge(i, j) for ( int k = 1 ; k <= n ; k ++ )
for ( int i = 1 ; i <= n ; i ++ ) for ( int j = 1 ; j <= n ; j ++ )
dis[ i ][ j ] = min( dis[ i ][ j ] ,
dis[ i ][ k ] + dis[ k ][ j ] ) ; // dis[ i ][ j ]: shortest path from i to j
ADVANTAGE
easy to implement
DISADVANTAGE
Cannot handle negative cycle
O( ) V
3DIJKSTRA'S ALGORITHM
Cannot handle negative edge Single-source
Greedy
O(E + V
2)
ALGORITHM (INITIALIZE)
Let the source be
Maintain an unvisited vertice set (intially, ) Maintain an array , where stores the current
known shortest path from the source to vertice . (initially, )
Maintain a variable storing the vertice currently being handled.
Set and let .
s U U = V
d[] d[i]
d[i] = INF, ∀i i
p
d[s] = 0 p = s
ALGORITHM (MAIN PART)
Repeat the following procedure until is empty
For all vertices adjacent to , let it be , update with Remove from .
For all vertices in , find the vertice with smallest , and assign it to .
p U q d[q]
d[p] + weight(p, q)
p U
U d[]
p
ALGORITHM (FINALE)
now stores the shortest path from to
Time complexity: (Better for dense graph)
Can also be implemented in time with priority queue. (Better for sparse graph)
d[i] s i
O(E + V
2)
O((E + V) log V)
SUMMARY
Why is it correct?
Why not negative edges?
IMPLEMENTATION (INITIALIZE)
bool vis[ N ] ; int vcnt = 0 ; int dis[ N ] ;
memset( vis , false , sizeof vis ) ; dis[ s ] = 0 ;
int p = s ;
IMPLEMENTATION (MAIN)
while ( true ) {
for ( ii x : v[ p ] ) if ( !vis[ x ] ) { int q = x.first , w = x.second ;
dis[ q ] = min( dis[ q ] , dis[ p ] + w ) ; }
vis[ p ] = true ; int nxtp = -1 ;
for ( int i = 0 ; i < n ; i ++ ) if ( !vis[ i ] ) {
if ( nxtp == -1 || dis[ i ] < dis[ nxtp ] ) nxtp = i ; }
if ( nxtp == -1 ) break ; else p = nxtp ;
}
BELLMAN-FORD ALGORITHM
Can handle negative cycles Single-source
O(V ⋅ E)
核心概念:放鬆(RELAX)
對一條邊 如果滿足 就更新
(u, v)
dis(u) + weight(u, v) < dis(v)
dis(v)
算法
初始化所有 為無窮大(起點設為 0)
對圖上的每一條邊放鬆一次
重複上面的步驟 次
dis(u)
V − 1
複雜度
O(V ⋅ E)
性質一
在沒負環的圖上
對任意節點 都有一條長度(經過的邊數)小於 的最
短路
v V
性質二
對於一個節點
若存在一條從 來(前一個點)的最短路
則從起點走 的最短路到 後再走 到 會是 的 一條最短路
v u
u u (u, v) v v
性質三
對於一個節點
若存在一條長度(經過的邊數)為 的最短路 則最多放鬆 輪後會得到這條最短路
v l
l
負環怎麼辦?
再做一輪?
再做
V − 1
輪?實作
struct edge {
int u , v , w ; } ;
vector< edge > E ; int dis[ N ] ;
for ( int i = 1 ; i < n ; i ++ ) for ( edge ed : E )
dis[ ed.v ] = min( dis[ ed.v ] , dis[ ed.u ] + ed.w ) ;