수학 → 그래프이론 에서 그래프란 ?
위상수학 Topology
연속변환 Continous에 대해 불변인 기하학적 객체의 특성을 연구하는 수학의 한 분야
쾨니히스베르크의 다리문제
https://t1.daumcdn.net/cfile/tistory/13614A4A4DB2409F06
위 문제를 수학적 구조로 보면
https://t1.daumcdn.net/cfile/tistory/2165353754929F9704
증명에 따르면 쾨니히스베르크의 다리는 모든 정점이 짝수개의 차수를 갖지 않으므로 오일러 경로가 아니다
해밀턴 경로를 찾는 문제는 최적 알고리즘이 없는 대표적인 NP-완전 Complete 문제다
해밀턴 순환 Hamiltonian Path
외판원 문제 Travelling Salesman Problem
해밀턴 문제와 외판원 문제의 NP 문제는 왜 다를까?
위 세 문제는 해밀턴 경로 > 해밀턴 순환 > 외판원 문제
와 같은 포함 관계를 이룬다
NP완전 문제의 조건
NP난해 문제의 조건
그래프 탐색Search 라고도 불리며,그래프의 각 정점을 방문하는 과정을 말함
그래프 순회 알고리즘
그래프 표현 방법
DFS 깊이 우선 탐색
재귀를 이용한 DFS 구현 수도코드
수도코드(pseudo-code)란 ?
Pseudo 가짜의 란 뜻으로 수도코드는 컴퓨터 프로그램이나 알고리즘이 수행해야할 내용을 우리가 사용하는 언어로 간략히 서술해 놓은것을 말함
언제 쓰는가?
코딩 입력을 시작하기 전, 사고를 좀더 명확히 정립하게 만들어주어 프로그램 설계하는데 도움을 줌
디버그를 수정하고 코드를 재분해 하는데 걸리는 시간을 단축할 수 있음
#DFS,BFS 구현을 위한 딕셔너리 활용 그래프 구조
graph = {
1: [2, 3, 4,],
2: [5],
3: [5],
4: [],
5: [6, 7],
6: [],
7: [3],
}
'''
DFS(G, v)
label v as discovered
for all directed edges from v to w that are in G.adjacentEdges(v) do
if vertex w is not labeled as discovered then
recursively call DFS(G, w)
정점 v의 모든 인접 유향(Directed) 간선들을 반복하라
'''
#재귀를 이용한 dfs 함수 선언
def recursive_dfs(v, discovered=[]):
# 방문했던 정점인 discoverd를 누적된결과로 만들기 위해 리턴하는 형태만 받아오도록 처리
discovered.append(v)
for w in graph[v]:
if not w in discovered:
discovered = recursive_dfs(w, discobered)
return discovered
f'recursive dfs: {recursive_dfs(1)}
'''
output
'recursive dfs: [1, 2, 3, 5, 6, 7, 3, 4]'
'''
12-7 순회를 위한 그래프
12-8 그림에서 막다른 곳에 도달할 때까지 연속으로 진행되는 탐색은 총 3 번
1번
2번
3번
스택을 이용한 반복 구조로 구현
#DFS,BFS 구현을 위한 딕셔너리 활용 그래프 구조
graph = {
1: [2, 3, 4,],
2: [5],
3: [5],
4: [],
5: [6, 7],
6: [],
7: [3],
}
'''
반복을 이용한 DFS 구현 수도코드
DFS-iterative(G, v)
let S be a stack
S.push(v)
while S is not empty do
v= S.pop()
if v is not labeled as discovered then
label v as discovered
for all edges from v to w in G.adjacentEdges(v) do
S.push(w)
스택을 활용하여 모든 인접 간선을 추출하고 다시 도착점인 정점을 스택에 삽입하는 구조
'''
def iterative_dfs(start_v):
discoverd = []
stack = [start_v]
while stack:
v = stack.pop()
if v not in discoverd:
discoverd.append(v)
for w in graph[v]:
stack.append(w)
return discoverd
f'iterative dfs: {iterative_dfs(1)}'
'''
output
'iterative dfs : [1, 4, 3, 5, 7, 6, 2]'
'''
재귀 DFS 와 스택 DFS 의 차이
BFS 너비 우선 탐색
최단경로를 찾는 다익스트라 알고리즘 등에 활용
다익스트라 알고리즘
큐를 이용한 반복 구조로 구현
#DFS,BFS 구현을 위한 딕셔너리 활용 그래프 구조
graph = {
1: [2, 3, 4,],
2: [5],
3: [5],
4: [],
5: [6, 7],
6: [],
7: [3],
}
'''
큐를 이용한 BFS 수도코드
BFS(G, start_v)
let Q be a queue
label start_v as discovered
Q.enqueue(start_v)
while Q is not empty do
v := Q.dequeue()
if v is the goal then
return v
for all edges from v to w in G.adjacentEdges(v) do
if w is not labeled as discovered then
label w as discovered
w.parent := v
Q.enqueue(w)
모든 인접 간선을 추춢하고 도착점인 정점을 큐에 삽입 하는 수도코드
'''
def iterative_bfs(start_v):
discovered = [start_v]
queue = [start_v]
while queue:
v = queue.pop(0)
for w in graph[v]:
if w not in discovered:
discovered.append(w)
queue.append(w)
return discovered
f'iterative bfs: {iterative_bfs(1)}'
'''
output
'iterative bfs: [1, 2, 3, 4, 5, 6, 7]'
'''
재귀 구현 불가
백트래킹은 해결책에 대한 후보를 구축해 나아가다 가능성이 없다고 판단되는 즉시 후보를 포기(백트랙Backtrack) 해 정답을 찾아가는 범용적인 알고리즘이다
제약 충족 문제 Constraint Satisfaction Problems에 특히 유용하다
백트래킹은 탐색을 하다가 더 갈 수 없으면 왔던 길을 되돌아가 다른 길을 찾는다
즉, DFS 는 백트래킹의 골격을 이루는 알고리즘이다
앞서 설명하였듯이 백트래킹은 주로 재귀로 구현한다
백트래킹은 가보고 되돌아오고를 반복한다
-예시 이미지 첨삭필요
부르트 포스 방법은 모든 경로를 반복하여 탐색해야 한다
-예시 이미지 첨삭필요
백트래킹 방법은 가능성이 없는 후보는 포기한다
위 그림에서 처럼 가능성이 없는 후보를 포기하는 과정을 트리의 가치지기 Pruning 이라 한다
제약충족문제란 수많은 제약조건Constraints을 충족하는 상태States를 찾아내는 수학 문제를 일컫는다