시작 지점과 종료 지점을 설정하여 최단 거리를 구한다
과정은 다익스트라와 비슷하지만
거리 계산시 H(노드에서 종료 노드까지의 거리)를 추가로 계산에 사용하고, 경로를 추적할 노드 정보가 추가된다.
1. 각 노드정보를 초기화
- 각 노드에 다른 노드까지의 거리를 설정하고 시작지점에서 최소 거리는 처음 무한대로 설정
- 각 노드에서 종료 노드까지의 거리를 설정
2. 시작 노드 설정
- 시작 노드의 최소 거리는 0으로 설정
- 시작 노드를 열린 노드 셋에 등록
3. 대상 노드를 찾는다
- 현재 등록된 열린 노드셋에서 F(G + H)가 가장 작은 노드를 찾는다
- 만약 대상이 없거나 대상 노드가 종료 노드인경우 종료
4. 대상 노드는 닫힌 노드 셋에 등록하고 열린 노드셋에서 제거
5. 대상 노드와 연결된 노드 중 다음 조건에 맞는 연결 노드를 찾는다
- 연결되어있는 노드(거리가 설정된 노드)
- 아직 처리되지 않은 노드(닫힌 노드 셋에 등록되지 않은 노드)
6. 대상 노드에 연결된 각 노드의 최소 거리를 조건에 따라 갱신
- 대상 노드의 G와 대상 노드와 연결된 노드까지의 거리를 더해 대상 노드를 거쳐 연결노드로 갈 때의 거리값(G)을 구한다
- 구한 G값을 연결노드의 기존 G와 비교하여 더 작다면 연결 노드의 G와 F를 갱신하고 부모 노드도 대상 노드로 변경
- 연결노드들은 열린 노드 셋에 등록
3 ~ 6번을 더이상 대상 노드가 없을 때까지 루프
#include <stdio.h>
#include <vector>
#include <set>
#include <list>
// 연결되지 않은 노드의 거리 값
#define INFINITY_DISTANCE (9999)
// 노드 리스트 카운트
#define NODE_LIST_COUNT (6)
//----------------------------------------------------------
// 노드 정보
//----------------------------------------------------------
struct Node
{
public:
// 노드 인덱스
int Index = -1;
//-----------------------------------------------------------
// 거리 정보
//-----------------------------------------------------------
// 시작 노드에서 해당 노드까지의 최소 거리
int Distance_G = INFINITY_DISTANCE;
// 해당 노드에서 끝노드까지의 거리
int Distance_H = 0;
// G + H
int Distance_F = 0;
// 해당 노드에서 연결된 노드의 거리정보를 설정
// 연결되어있지 않는경우 INFINITY_DISTANCE
std::vector<int> LinkNodesDistance;
// 부모 노드
Node* ParentNode = nullptr;
public:
// 거리 정보가 갱신 되면 Distance_F를 갱신
void UpdateDistanceF()
{
Distance_F = Distance_G + Distance_H;
}
};
// 노드 정보 리스트
std::vector<Node> NodeList;
// 열린 노드 인덱스 리스트
std::set<int> OpenNodeIndexSet;
// 닫힌 노드 인덱스 리스트
std::set<int> CloseNodeIndexSet;
//---------------------------------------------------------------
// 기능
//---------------------------------------------------------------
// 노드 정보 리스트 초기화
// 여기서 도착노드는 5번 노드로 정하고 각 노드에서 5번노드까지의 거리를 설정
void InitNodeList()
{
// 노드 정보 설정
NodeList.resize(NODE_LIST_COUNT);
// 대상노드
Node* targetNode = nullptr;
// 0번 노드 설정
targetNode = &(NodeList[0]);
targetNode->Index = 0;
targetNode->Distance_H = 35;
targetNode->LinkNodesDistance.resize(NODE_LIST_COUNT);
targetNode->LinkNodesDistance[0] = 0;
targetNode->LinkNodesDistance[1] = 10;
targetNode->LinkNodesDistance[2] = 30;
targetNode->LinkNodesDistance[3] = 20;
targetNode->LinkNodesDistance[4] = INFINITY_DISTANCE;
targetNode->LinkNodesDistance[5] = INFINITY_DISTANCE;
// 1번 노드 설정
targetNode = &(NodeList[1]);
targetNode->Index = 1;
targetNode->Distance_H = 23;
targetNode->LinkNodesDistance.resize(NODE_LIST_COUNT);
targetNode->LinkNodesDistance[0] = 10;
targetNode->LinkNodesDistance[1] = 0;
targetNode->LinkNodesDistance[2] = 15;
targetNode->LinkNodesDistance[3] = INFINITY_DISTANCE;
targetNode->LinkNodesDistance[4] = INFINITY_DISTANCE;
targetNode->LinkNodesDistance[5] = INFINITY_DISTANCE;
// 2번 노드 설정
targetNode = &(NodeList[2]);
targetNode->Index = 2;
targetNode->Distance_H = 10;
targetNode->LinkNodesDistance.resize(NODE_LIST_COUNT);
targetNode->LinkNodesDistance[0] = 30;
targetNode->LinkNodesDistance[1] = 15;
targetNode->LinkNodesDistance[2] = 0;
targetNode->LinkNodesDistance[3] = INFINITY_DISTANCE;
targetNode->LinkNodesDistance[4] = 10;
targetNode->LinkNodesDistance[5] = INFINITY_DISTANCE;
// 3번 노드 설정
targetNode = &(NodeList[3]);
targetNode->Index = 3;
targetNode->Distance_H = 19;
targetNode->LinkNodesDistance.resize(NODE_LIST_COUNT);
targetNode->LinkNodesDistance[0] = 20;
targetNode->LinkNodesDistance[1] = INFINITY_DISTANCE;
targetNode->LinkNodesDistance[2] = INFINITY_DISTANCE;
targetNode->LinkNodesDistance[3] = 0;
targetNode->LinkNodesDistance[4] = INFINITY_DISTANCE;
targetNode->LinkNodesDistance[5] = 15;
// 4번 노드 설정
targetNode = &(NodeList[4]);
targetNode->Index = 4;
targetNode->Distance_H = 10;
targetNode->LinkNodesDistance.resize(NODE_LIST_COUNT);
targetNode->LinkNodesDistance[0] = INFINITY_DISTANCE;
targetNode->LinkNodesDistance[1] = INFINITY_DISTANCE;
targetNode->LinkNodesDistance[2] = 10;
targetNode->LinkNodesDistance[3] = INFINITY_DISTANCE;
targetNode->LinkNodesDistance[4] = 0;
targetNode->LinkNodesDistance[5] = 10;
// 5번 노드 설정
targetNode = &(NodeList[5]);
targetNode->Index = 5;
targetNode->Distance_H = 0;
targetNode->LinkNodesDistance.resize(NODE_LIST_COUNT);
targetNode->LinkNodesDistance[0] = INFINITY_DISTANCE;
targetNode->LinkNodesDistance[1] = INFINITY_DISTANCE;
targetNode->LinkNodesDistance[2] = INFINITY_DISTANCE;
targetNode->LinkNodesDistance[3] = 15;
targetNode->LinkNodesDistance[4] = 10;
targetNode->LinkNodesDistance[5] = 0;
}
// 다음 노드를 찾는다
Node* FindNextCheckNode()
{
int minValue = INFINITY_DISTANCE;
Node* minNode = nullptr;
// 열린 노드중에 최소값이 가장 작은노드를 찾는다
for (auto iter : OpenNodeIndexSet)
{
const int nodeIndex = iter;
Node* node = &(NodeList[nodeIndex]);
// 해당노드의 최소값이 더작다면 갱신
if (node->Distance_F < minValue)
{
minNode = node;
minValue = node->Distance_F;
}
}
return minNode;
}
// 연결노드의 최소값 갱신
void UpdateLinkNode(Node* inNode)
{
// 넘어온 노드의 링크 노드 정보 루프
for (int nodeIndex = 0; nodeIndex < NODE_LIST_COUNT; ++nodeIndex)
{
// 대상 노드와 연결되어있지 않다면 처리하지 않는다
const int linkNodeDistance = inNode->LinkNodesDistance[nodeIndex];
if (INFINITY_DISTANCE == linkNodeDistance) {
continue;
}
// 이미 처리된 노드인경우 처리하지 않는다
if (CloseNodeIndexSet.end() != CloseNodeIndexSet.find(nodeIndex)) {
continue;
}
// 현재노드에서 링크노드의 거리를 얻는다
const int checkDistance = inNode->Distance_G + linkNodeDistance;
// 링크 노드
Node* linkNode = &(NodeList[nodeIndex]);
// 체크 거리가 링크노드에 설정된 거리보다 작다면 해당 거리로 재설정
if (checkDistance < linkNode->Distance_G)
{
linkNode->Distance_G = checkDistance;
linkNode->UpdateDistanceF();
linkNode->ParentNode = inNode;
}
// 열린 노드에 추가
OpenNodeIndexSet.insert(linkNode->Index);
}
}
int main(void)
{
// 노드 정보를 초기화
InitNodeList();
// 사용할 시작 노드 인덱스
const int startNodeIndex = 0;
// 이건 고정(각노드에서 종료노드까지의 거리가 미리 정해저야 해서)
const int endNodeIndex = 5;
// 시작노드는 시작지점에서 해당 노드까지의 최소 비용을 0으로 설정
{
Node* startNode = &NodeList[startNodeIndex];
startNode->Distance_G = 0;
startNode->UpdateDistanceF();
}
// 열린 노드에 등록
OpenNodeIndexSet.insert(startNodeIndex);
// 처리
while (true)
{
// 다음 체크할 노드가 없거나 끝 노드와 동일하다면 종료
Node* checkNode = FindNextCheckNode();
if (nullptr == checkNode || checkNode == &NodeList[endNodeIndex]) {
break;
}
// 체크한 노드는 닫힌 노드셋에 추가
CloseNodeIndexSet.insert(checkNode->Index);
// 열린 노드 정보에서는 제거
OpenNodeIndexSet.erase(checkNode->Index);
// 해당 노드와 연결된 노드의 최소값을 갱신
UpdateLinkNode(checkNode);
}
// 결과 노드에서 부터 연결된 노드를 찾는다
std::list<Node*> pathList;
{
Node* targetNode = &NodeList[endNodeIndex];
while (nullptr != targetNode)
{
pathList.push_front(targetNode);
targetNode = targetNode->ParentNode;
}
}
for (auto node : pathList)
{
printf("-> node(%d) ", node->Index);
}
return 0;
}
'알고리즘' 카테고리의 다른 글
[알고리즘] 여러개의 그룹을 조합했을때 경우의 수 출력 (3) | 2024.10.09 |
---|---|
[알고리즘] A* - 그리드 기반 (2) | 2023.10.01 |
[알고리즘] 용어 (0) | 2023.09.29 |
[알고리즘] 다익스트라(Dijkstra) (0) | 2023.08.26 |