κ·Έλž˜ν”„ μš©μ–΄ 정리

  • κ·Έλž˜ν”„λŠ” λ‘œλ΄‡μ΄ μ΅œλ‹¨κ²½λ‘œλ₯Ό κ³„μ‚°ν•΄μ„œ 움직일 λ•Œλ‚˜ λ‚΄λΉ„κ²Œμ΄μ…˜ 경둜λ₯Ό μ•ˆλ‚΄ν• λ•Œ, μ§€ν•˜μ² μ—­μ„ 어디에 건섀해야 κ°€μž₯ νš¨μœ¨μ μΈμ§€ κ³„μ‚°ν•˜λŠ” λ“± 맀우 ν­λ„“κ²Œ μ‚¬μš©
  • κ·Έλž˜ν”„λŠ” 정점(vertex)의 집합 V(G)와 에지(edge)의 집합 E(G)둜 μ •μ˜
\[G = (V, E)\]

무방ν–₯ κ·Έλž˜ν”„

  • 무방ν–₯κ·Έλž˜ν”„(undirected graph)인데, μ΄λŠ” (A,B)은 (B,A)와 κ°™λ‹€λŠ” 의미
  • 정점 κ°œμˆ˜κ°€ n개라면 이 κ·Έλž˜ν”„μ˜ μ΅œλŒ€ 에지 κ°œμˆ˜λŠ” n * (n-1) /2

png

\[G = (V, E)\] \[V(G) = {A,B,C,D}\] \[E(G) = {(A,B),(A,D),(B,C),(B,D),(C,D)}\]

λ°©ν–₯ κ·Έλž˜ν”„

  • 엣지에 λ°©ν–₯이 μžˆλŠ” κ·Έλž˜ν”„

png

\[G = <V, E>\] \[V(G) = { A,B,C,D }\] \[E(G) = {<A,B><A,D>,<B,C>,<B,D>,<C,D>}\]

자기 κ°„μ„ 

png

  • 정점이 tail 이자 λ™μ‹œμ— head 인 κ·Έλž˜ν”„

λ©€ν‹°κ·Έλž˜ν”„

  • 일반적으둜 κ·Έλž˜ν”„μ—μ„œλŠ” 에지 쀑볡 인정 ν•˜μ§€ μ•ŠλŠ”λ‹€.
  • 이 쀑볡 에지λ₯Ό μΈμ •ν•˜λŠ” 자료 ꡬ쑰λ₯Ό λ©€ν‹° κ·Έλž˜ν”„(multi-graph)

png

인접

  • 두 정점을 μ—°κ²°ν•˜λŠ” 간선이 μžˆμ„ λ•Œ μ„œλ‘œ μΈμ ‘ν•œλ‹€κ³  ν‘œν˜„

경둜

  • κ²½λ‘œλž€, 정점 Vi μ—μ„œ VjκΉŒμ§€μ˜ 정점 μˆœμ„œλ₯Ό 의미
  • κ²½λ‘œκΈΈμ΄λŠ” 에지 개수

png

μ—°κ²°λœ κ·Έλž˜ν”„

png

  • μ–΄λ–€ 정점 u와 λ‹€λ₯Έ μ–΄λ–€ μž„μ˜μ˜ 정점 vλ₯Ό κ³¨λžμ„ λ•Œ 정점 사이에 κ²½λ‘œκ°€ 있으면 이λ₯Ό μ—°κ²°λ˜μ—ˆλ‹€ 라고 ν•œλ‹€.
\[G = (V, E)\] \[V(G) = {0,1,2,3,4,5,6}\] \[E(G) = {(1,2),(1,5),(2,5),(3,4),(4,6)}\]
  • 정점 집합 {1,2,5},{3,4,6}을 각각 μ—°κ²°μš”μ†ŒλΌκ³  ν•œλ‹€.

차수

  • 무방ν–₯ κ·Έλž˜ν”„μ˜ 경우 μ–΄λ–€ 정점 v의 차수 d(v)λŠ” 정점 vκ°€ λΆ€μ†λœ 에지 개수
  • 무방ν–₯ κ·Έλž˜ν”„μΌ 경우, 정점 A에 λΆ€μ†λœ 에지가 μ„Έκ°œμ΄λ―€λ‘œ d(A) = 3
  • λ°©ν–₯ κ·Έλž˜ν”„μΌ 경우, μ§„μž…μ°¨μˆ˜μ™€ μ§„μΆœμ°¨μˆ˜μ˜ ν•©
  • μ§„μž…μ°¨μˆ˜λŠ” 정점 v둜 λ“€μ–΄μ˜€λŠ” 에지 개수
  • μ§„μΆœμ°¨μˆ˜λŠ” 정점 vμ—μ„œ λ‚˜κ°€λŠ” 에지 개수

png

png

  • 뢀속 : 정점 u와 정점 v 사이에 에지 (u,v)κ°€ μ‘΄μž¬ν•  λ•Œ 에지 (u,v)λ₯Ό 정점 u에 λΆ€μ†λ˜μ—ˆλ‹€λΌκ³  ν‘œν˜„

κ·Έλž˜ν”„λ₯Ό ν‘œν˜„ν•˜λŠ” 두가지 방법: λ„μ‹œμ™€ λ„μ‹œλ₯Ό μ΄μ–΄λ³΄μž

  • κ·Έλž˜ν”„λ₯Ό ν‘œν˜„ ν•˜λŠ” 두가지 방법에 인접 리슀트(adjacency list) 와 인접행렬(adjacemcy matrix)이 μžˆλ‹€.

png

  • λ°°μ—΄ ν•œκ°œμ™€ μ—°κ²°λ¦¬μŠ€νŠΈλ“€λ‘œ κ΅¬μ„±λ˜μ–΄μžˆμœΌλ©°, 정점이 λ°°μ—΄μ˜ μΈλ±μŠ€κ°€ λœλ‹€.
  • μ–΄λ–€ 정점 v에 λŒ€ν•΄ μΈμ ‘ν•œ λͺ¨λ“  λ…Έλ“œλ₯Ό νƒμƒ‰ν•˜λŠ” 연산에 λŒ€ν•œ λΉ…μ˜€λ₯Ό μƒκ°ν•΄λ³΄μž
    • μ •λ‹΅ : λͺ¨λ“  정점을 쑰사할 ν•„μš” 없이 ν•΄λ‹Ή μ •μ μ˜ μΈμ ‘ν•œ μ •μ λ“€λ§Œ μ‘°μ‚¬ν•˜λ©΄λ˜κΈ° λ•Œλ¬Έμ— –> λΉ…μ˜€ O(d(v))

png

  • 각각의 행을 μ •μ μœΌλ‘œ 보고 열을 μžμ‹ μ„ ν¬ν•¨ν•œ λ‹€λ₯Έ 정점이라고 μƒκ°ν•˜λ©΄ λœλ‹€.
  • matrix[1][3]의 값은 λ¬΄μ—‡μΌκΉŒμš”?
    • μ •λ‹΅ : 1
  • 정점 n 에 λŒ€ν•΄ μΈμ ‘ν•œ λͺ¨λ“  λ…Έλ“œλ₯Ό νƒμƒ‰ν•˜λŠ” 연산에 λŒ€ν•œ λΉ…μ˜€λ₯Ό μƒκ°ν•΄λ³΄μž
    • μ •λ‹΅: 정점 κ°œμˆ˜κ°€ n 이라고 ν–ˆμ„λ•Œ O(n)
  • (2,3)κ°€ μžˆλŠ”μ§€ μ—¬λΆ€λ₯Ό ν™•μΈν•˜λŠ” 연산에 λŒ€ν•œ λΉ…μ˜€λ₯Ό μƒκ°ν•΄λ³΄μž
    • μ •λ‹΅ : matrix[2][3]만 ν™•μΈν•˜λ©΄ 되기 λ•Œλ¬Έμ— –> O(1)

κ·Έλž˜ν”„μ˜ λͺ¨λ“  λ…Έλ“œ λ°©λ¬Έ: λͺ¨λ“  λ„μ‹œλ₯Ό μ—¬ν–‰ν•΄λ³΄μž

  • λͺ¨λ“  λ…Έλ“œλ₯Ό μˆœνšŒν•˜λŠ” 방법은 두가지 : λ„ˆλΉ„ μš°μ„  탐색(Breadth Frist Search, BFS)κ³Ό 깊이 μš°μ„  탐색 (Depth First Search, DFS)
  • λ„ˆλΉ„ μš°μ„  탐색은 큐λ₯Ό μ΄μš©ν•΄μ„œ κ΅¬ν˜„, 깊이 μš°μ„  탐색은 μŠ€νƒμ„ 기반으둜 κ΅¬ν˜„λ©λ‹ˆλ‹€.

λ„ˆλΉ„ μš°μ„  탐색(Breadth Frist Search, BFS) : 탐색을 ν• λ•Œ λ„ˆλΉ„λ₯Ό μš°μ„ μœΌλ‘œ ν•˜μ—¬ 탐색을 μˆ˜ν–‰ν•˜λŠ” 탐색 μ•Œκ³ λ¦¬μ¦˜

png

png

png

png

png

png

  • 결과적으둜 λ…Έλ“œμ˜ 탐색 μˆœμ„œ, 즉 큐에 μ‚½μž…ν•œ μˆœμ„œλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.
    • 1 -> 2 -> 3 -> 8 -> 4 -> 5 -> 6 -> 7
from queue import Queue

class Graph:
	def __init__(self, vertex_num):
        # 인접 리슀트둜 κ΅¬ν˜„
		self.adf_list = [ [] for _ in range(vertex_num)]
        # λ°©λ¬Έ μ—¬λΆ€ 체크
		self.visited = [ False for _ in arnage(vertex_num)]
	
    def add_edge(self, u, v):
        self.adj_list[u].append(v)
        self.adj_list[v].append(u)

    def init_visited(self):
        for i in range(len(self.visited)):
            self.visited[i].False   
def bfs(self, v):
    q = Queue()
    # λ°©λ¬Έ 체크 리슀트λ₯Ό μ΄ˆκΈ°ν™”ν•©λ‹ˆλ‹€.
    self.init_visited()

    # 첫번째 정점을 큐에 λ„£κ³  λ°©λ¬Έ 체크
    q.put(v)
    self.visited[v] = True

    while not q.empty():
        v = q.get()
        # λ°©λ¬Έ
        print(v, end=" ")
        # 인접 리슀트λ₯Ό μ–»μ–΄ μ˜΅λ‹ˆλ‹€.
        adj_v = self.adj_list[v]
        for u in adj_v:
            if not self.visited[u]:
                q.put(u)
                self.visited[u] = True

깊이 μš°μ„  탐색(Depth First Search, DFS) : 탐색을 ν• λ•Œ λ„ˆλΉ„λ₯Ό μš°μ„ μœΌλ‘œ ν•˜μ—¬ 탐색을 μˆ˜ν–‰ν•˜λŠ” 탐색 μ•Œκ³ λ¦¬μ¦˜

  • 탐색을 ν• λ•Œ 깊이λ₯Ό μš°μ„ μœΌλ‘œ ν•˜μ—¬ 탐색을 μˆ˜ν–‰ν•˜λŠ” 탐색 μ•Œκ³ λ¦¬μ¦˜
  • ν•œ λ…Έλ“œλ₯Ό μ‹œμž‘μœΌλ‘œ λ‹€μŒ λ…Έλ“œλ‘œ λ„˜μ–΄κ°€κΈ° 전에 ν•΄λ‹Ή λ…Έλ“œλ₯Ό μ™„λ²½ν•˜κ²Œ νƒμƒ‰ν•œλ‹€.

png

png

png

png

png

png

png

png

png

png

png

png

png

  • 결과적으둜 λ…Έλ“œμ˜ 탐색 μˆœμ„œ, 즉 μŠ€νƒμ— μ‚½μž…ν•œ μˆœμ„œλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.
    • 1 -> 2 -> 8 -> 6 -> 7 -> 3 -> 4 -> 5
def dfs_recursion(self, v):
    # λ°©λ¬Έ
    print(v, end=" ")
    # 방문 체크
    self.visited[v] = True

    adj_v = self.adj_list[v]
    for u in adj_v:
        if not self.visited[u]:
            self.dfs_recursion(u)

def dfs(self,v):
    self.init_visited()
    self.dfs_recursion(v)

Source

https://heytech.tistory.com/55

https://heytech.tistory.com/56