그래프
개론
일반적으로 알고 있는 그래프와는 조금 다름
노드와 에지
노드 : 중간 지점
에지 : 노드끼리를 연결하는 길
광범위한 의미
하나의 네트워크의 기호적인 표현
전화
www
전자 회로
인공 신경망
좀 더 형식적인 기술
G = {N, E}
N : 0 ~ (N-1)
E : 3-5 / 19-7
가중치 존재
거리
길의 특성(오르막, 늪 등)
트리
비순환인 모든 그래프를 포함하는 그래프의 부분집합
그래프 밀도
밀집하거나
성기거나
다이그래프
에지의 방향 존재
16-6 : 16->6 ( ! 6->16 )
16 : 근원 노드(source node)
6 : 목적 노드(destination node)
무방향 그래프 == 쌍방향 다이그래프
게임 AI에서의 그래프
항해 그래프(navgraph)
게임 에이전트가 방문할 수 있는 게임 환경의 모든 장소와 그 지점들 사이의 모든 연결의 추상화
종속 그래프(dependency graph)
여러 빌딩, 물자, 유닛과 선우에 적용될 수 있는 기술들 사이의 종속성을 표현하기 위해 사용
상태 그래프(state graph)
시스템이 존재할 수 있는 모든 가능한 상태와 그 상태들 사이의 전환을 표현
루트 노드
부모 상태 - 자식 상태
분기율(branching factor)
각 부모 노드에서 퍼져 나가는 자식 노드의 평균 개수
대부분 분기율이 높기 때문에 목표 상태 쪽으로 탐색을 지시해 한 번에 몇 개의 노드만 생성되고 탐색
그래프 클래스 구현하기
개론
표현 자료구조
인접 행렬(adjacency matrix)
직관적
용량 비효율
N의 제곱
인접 리스트(adjacency list)
성긴 그래프에 효율적
공간 낭비 x
N+E
GraphNode Class
노드가 필요로 하는 최소 정보를 캡슐화
template< class extra_info = void* > class NavGraphNode : public GraphNode
GraphEdge Class
두 개의 노드 사이의 연결을 나타내기 위해 필요한 기본 정보를 캡슐화
가중치
가중치가 동일하다면 그 필드를 생략함으로써 메모리 절약
가중치가 두 노드 사이의 거리라면 Distance 함수 사용
SparseGraph Class
노드와 에지에 접근할 수 있게끔
인텍스 사용
컨테이너
vector<node_type> NodeVector
list<edge_type> EdgeList
vector<EdgeList> EdgeListVector
그래프 탐색 알고리즘
개론
탐색 알고리즘이 하는 일
그래프의 모든 노드 방문
두 노드 사이의 어떠한 경로를 찾음
두 노드 사이의 최적 경로를 찾음
무정보 그래프 탐색
에지 비용에 대한 언급 없이 그래프 탐색
깊이 우선 탐색
모든 노드와 에지가 방문될 것임을 보장
알고리즘 구현
멤버
m_Visited : unvisited
방문된 모든 노드들의 인덱스 기록
m_Route : no_parent_assigned
목표까지의 경로 보유
std::Stack 사용
순서
생성자 -> Search()
std::stack<const Edge*> stack;
Edge Dummy();
stack.push(&Dummy);
while(!stack.empty())
const Edge* Next = stack.top()
stack.pop()
m_Route[Next->To] = Next->From()
m_Visited[Next->To()] = visited
if(Next->To() == m_iTarget) return true;
for( ConstEdgeItr )
if(m_Visited[pE->To()] == unvisited) stack.push(pE);
GetPathToTarget() 에서 목표까지의 경로 반환
너비 우선 탐색
가장 적은 에지를 방문하는 경로를 보장
멤버
m_Visited : unvisited
방문된 모든 노드들의 인덱스 기록
m_Route : no_parent_assigned
목표까지의 경로 보유
std::queue 사용
알고리즘 구현
std::queue<const Edge*> Q
const Edge Dummy()
Q.push(&Dummy)
m_Visited[m_iSource] = visited;
while(!Q.empty())
const Edge* Next = Q.front();
Q.pop();
m_Route[Next->To()] = Next->From();
if(Next->To() == m_iTarget) return true;
for(ConstEdgeItr)
if(m_Visited[pE->To()] = visited)
Q.push(pE);
m_Visited[pE->To()] = visited;
비용 기반 그래프 탐색
에지 완화(Edge relaxation)
지금까지 발견된 가장 좋은 경로(BDSF)에 대한 정보 수집
최단 경로 트리(Shortest Path Tree, SPT)
어떤 노드에서 근원 노드까지 최단 경로를 나타내는 그래프의 부트리(sub-tree)
Dijkstra Algorithm
인덱스 우선순위 큐(indexed Priority Queue, iPQ) 사용
양방향 힙 사용
PQ의 앞에 있는 노드는 근원 노드에 가장 가까운 SPT에 아직 없는 노드라는 것을 보장
알고리즘 구현
IndexedPriorityQLow<double> pq
pq.Insert(m_iSource)
while(!Q.empty())
int NextClosestNode = pq.Pop()
.....
BFS처럼, Dijkstra 알고리즘은 너무 많은 에지를 검사
A* Algorithm
특별한 Dijkstra
휴리스틱(heuristic)
각 노드에서 목표까지의 비용을 추정해 탐색 속도 개선 가능
유클리디언(Euclidean) 거리 사용
노드들 사이의 직선 거리
Dijkstra와의 차이점
탐색 변경(우선순위 큐)의 노드들의 비용 계산
F = G + H
G : 노드에 이르는 누적 비용
H : 목표까지 거리의 휴리스틱 추정
구현하기
휴리스틱을 템플릿 매개변수로 설정
자체 제작 휴리스틱을 사용하기 쉽게 하기 위해
에지 완화 땐 Gcsot, PQ엔 Fcost 사용
맨하탄 거리 휴리스틱
가로와 세로 방향의 변이의 합
제곱근이 필요없으므로 유클리디언 휴리스틱보다 빠름