반응형

가중치는 서울 교통 공사 사이버 스테이션(http://www.seoulmetro.co.kr/kr/cyberStation.do) 에서

나오는 거리(km)를 기반으로 하였음

 

서울교통공사 사이버 스테이션

요일 선택 평일 토요일 공휴일 시 선택 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 분 선택 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 5

www.seoulmetro.co.kr

 

/*
다익스트라 알고리즘

*/

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

#define INF 1000 //무한, 인접해있지 않은 경우 무한으로 처리, 
//여기서는 가중치를 다 더해서 나올수 없는 큰수 1000으로 하였음

//지하철 노선도
#define VERTEX_COUNT 13
int adj[VERTEX_COUNT][VERTEX_COUNT] =
{
	{INF, 9, INF, 8, INF, INF, 6, 10, INF, INF, INF, INF, INF},      // 0. 종로3가 : 종로5가, 종각, 을지로3가, 을지로4가
	{9, INF, 8, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF},   // 1. 종로5가 : 종로3가, 동대문
	{INF, 8, INF, INF, INF, INF, INF, INF, 7, INF, INF, INF, INF},   // 2. 동대문 : 종로5가, 동대문역사문화공원
	{8, INF, INF, INF, 10, INF, INF, INF, INF, INF, INF, INF, INF},  // 3. 종각 : 종로3가, 시청
	{INF, INF, INF, 10, INF, 7, INF,  INF, INF, 11, INF, INF, INF},  // 4. 시청 : 종각, 을지로 입구, 서울역 
	{INF, INF, INF, INF, 7, INF, 8,  INF, INF, INF, INF, INF, INF},  // 5. 을지로입구 : 시청, 을지로3가
	{6, INF, INF, INF, INF, 8, INF,  6, INF, INF, INF, INF, 7},      // 6. 을지로3가 : 종로3가, 을지로입구, 을지로4가, 충무로
	{10, INF, INF, INF, INF, INF, 6, INF, 10, INF, INF, INF, INF},   // 7. 을지로4가 : 종로3가, 을지로3가, 동대문역사문화공원
	{INF, INF, 7, INF, INF, INF, INF, 10, INF, INF, INF, INF, 13},   // 8. 동대문역사문화공원 : 동대문, 을지로4가, 충무로
	{INF, INF, INF, INF, 11, INF, INF,  INF, INF, INF, 9, INF, INF}, // 9. 서울역 : 시청, 회현
	{INF, INF, INF, INF, INF, INF, INF, INF, INF, 9, INF, 7, INF},   // 10. 회현 : 서울역, 명동
	{INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, 7, INF, 7},   // 11. 명동 : 회현, 충무로
	{INF, INF, INF, INF, INF, INF, 7, INF, 13, INF, INF, 7, INF}     // 12. 충무로 : 을지로3가, 동대문역사문화공원, 명동
};

enum eStation
{
	종로3가,
	종로5가,
	동대문,
	종각,
	시청,
	을지로입구,
	을지로3가,
	을지로4가,
	동대문역사문화공원,
	서울역,
	회현,
	명동,
	충무로
};

char* vertexToStationName(int _vertexIndex); //정점 인덱스 -> 문자열 정점이름

//경로 확인 하기 위한 구조체, 간선의 시작점과 끝점을 의미
typedef struct _tagRoutePair
{
	int ParentV; //시작점
	int ChildV; //끝점
} ROUTEPAIR;

void Dijkstra(int _startV, int _endV)
{
	bool visited[VERTEX_COUNT] = { 0 }; //방문기록
	int distance[VERTEX_COUNT]; //시작점에서 각정점까지의 최소 가중치(최단거리) 기록
	ROUTEPAIR routePairs[VERTEX_COUNT] = { 0 }; //경로확인을 위한 간선 저장 배열
	
	//최소가중치 기록 배열 초기화
	for (int i = 0; i < VERTEX_COUNT; i++)
	{
		distance[i] = INF;
	}
	//distance[_startV] = 0;

	//주변 정점들과의 최소 가중치 기록하기
	for (int i = 0; i < VERTEX_COUNT; i++)
	{
		if (adj[_startV][i] != INF)
		{
			distance[i] = adj[_startV][i];
		}
	}
	visited[_startV] = true;
	routePairs[_startV].ParentV = _startV;

	int curretV = _startV; 
	for(int i = 0; i < VERTEX_COUNT - 1; i++)
	{
		int min = INF;
		int minIdx = curretV;

		for (int i = 0; i < VERTEX_COUNT; i++) //방문하지 않고, 최소 가중치 기록중 제일 낮은 가중치를 가지는 정점 찾기
		{
			if (!visited[i]) 
			{
				if (min > distance[i])
				{
					min = distance[i];
					minIdx = i; 
				}
			}
		}
		
		//기준 정점 초기화 및 방문 처리
		curretV = minIdx; 
		visited[curretV] = true;

		//방문한 정점을 기준으로 최소 가중치 배열 수정
		for (int i = 0; i < VERTEX_COUNT; i++)
		{
			if (!visited[i])
			{
				if (distance[curretV] + adj[curretV][i] < distance[i]) //이전경로 가중치 + 인접경로(새경로) 가중치
				{
					//경로 저장
					routePairs[curretV].ChildV = i;
					routePairs[i].ParentV = curretV;
				
					distance[i] = distance[curretV] + adj[curretV][i]; // 더 빠른 경우 초기화
				}
			}
		}
	
	}

	//반드시 adj 0번째 배열을 _start로 해야 아래로직이 무한루프 돌지 않고 잘동작함
	//_start 가 adj[0] 이 아닐 경우, 무한루프

	//경로 확인 하기
	int routeStack[VERTEX_COUNT] = { 0 };
	int RoutesCount = 0;
	routeStack[RoutesCount++] = _endV;
	int now = _endV;
	while(1)
	{
		if (routePairs[now].ParentV == _startV)
		{
			routeStack[RoutesCount++] = _startV;
			break;
		}
		now = routePairs[now].ParentV;
		routeStack[RoutesCount++] = now;
	}

	for (int i = RoutesCount - 1; i >= 0; i--)
	{
		
		if (i == RoutesCount - 1)
		{
			printf("%s 시작\n", vertexToStationName(routeStack[i]));
		}
		else if (i == 0)
		{
			printf("%s 도착\n", vertexToStationName(routeStack[i]));
		}
		else
		{
			printf("%s 방문\n", vertexToStationName(routeStack[i]));
		}
	}

}

char* vertexToStationName(int _vertexIndex)
{
	enum eStation e = _vertexIndex;
	switch (e)
	{
	case 종로3가:
		return "종로3가";
	case 종로5가:
		return "종로5가";
	case 동대문:
		return "동대문";
	case 종각:
		return "종각";
	case 시청:
		return "시청";
	case 을지로입구:
		return "을지로입구";
	case 을지로3가:
		return "을지로3가";
	case 을지로4가:
		return "을지로4가";
	case 동대문역사문화공원:
		return "동대문역사문화공원";
	case 서울역:
		return "서울역";
	case 회현:
		return "회현";
	case 명동:
		return "명동";
	case 충무로:
		return "충무로";
	default:
		return "없음";
	}
}


int main()
{
	Dijkstra(종로3가, 회현);
	
	return 0;
}

test 1

 

 

test 2

 

반응형
반응형

다익스트라(Dijkstra) 알고리즘

  • 에츠허르 비버 데이크스트라(Edsger Wybe Dijkstra) 1956년에 고안했으며 1959년 발표

  • 하나의 시작 정점에서 모든 다른 정점까지 최소비용의 인접정점을 선택하여 최단경로를 찾는 알고리즘

  • 입력 그래프에서 간선들의 가중치가 모두 0 이상인경우에 쓰임, 음수 가중치는 지원되지 않음(벨만-포드 알고리즘은 음수 가중치 허용)

  • 최단 경로는, 경로의 길이 순으로 정해짐

  • 다이나믹 프로그래밍 문제(큰문제를 작은 문제로 나누어 푸는 문제) 분류, 최단거리는 여러 개의 최단거리로 이루어져있기 때문이다

  • 가중치를 계산해서 효율적인 부터 방문하는 알고리즘

  • 인공위성 GPS 소프트웨어 등에서 가장 많이 사용됨


다익스트라 알고리즘 순서

  1. 시작점을 기준으로 아직 방문하지 않았고 인접한 정점들까지의 최소 가중치 정리

  2. 최소 가중치들 중에 아직 방문하지 않으면서 제일 작은 가중치를 가진 정점 선별

  3. 선별한 정점 방문, 방문한 정점 주변에 방문하지 않고 인접한 정점들을 파악

  4. 방문하지 않고 인접한 정점들중 시작점을 기준으로 해당 정점들까지의 최소 가중치 구해서 비교한뒤 빠르면 정리해놓은 최소 가중치를 수정, 느리면 그대로둠

(현재 기준점 까지의 최소가중치)+(인접한 정점까지의 가중치) < 현재 기록되어있는 최소 가중치

 

5. (전체 정점 개수 - 1(시작점)) 만큼 2~4 과정 반복

 

 

 

 

다익스트라 알고리즘 동작 과정 파헤치기

  1. 시작 정점을 기준으로 모든 정점에 이르는 최소 가중치(최단거리) 구해본다 이때 인접한 정점들은 가중치 계산이 되지만, 인접하지 않은 정점들은 어떤 점들을 경유해서 가야 될텐데, 아직 어떤점들을 지나갈지 모르므로 가중치가 무한(0 아닌 모든 가중치들의 합보다 일정한 하나의 )이라고 한다.

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

INF

8

INF

INF

6

10

INF

INF

INF

INF

INF

A_A A에서 A까지 도달하는 거리므로 사실상 0 다름없다.

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2. 인접한 정점들중 제일 낮은 가중치를 가진 정점(해당 예시에서는 G = 6) 방문처리 한다.

3. 방문한 정점을 기준으로 다시 인접하며, 아직 방문하지 않은 정점들을 찾는다,

이때 아까 인접하지 않았서 가중치를 무한으로 했던 정점들도 발견할 있는데, 지금 기준 정점(지금까지 제일 낮은 가중치) 경유하여 오게 되므로, 지금 기준 정점까지의 최소 가중치 + 해당 정점들 까지의 가중치 현재 기록되있는 최소가중치와 비교하여 빠르면 기입하고, 빠르지 않으면 그대로 둔다.

 

A_F = INF > A_G(6) + G_F(8) ? A_G(6) + G_F(8) : A_F(INF); //바뀜

A_H = 10 > A_G(6) + G_H(6) ? A_G(6) + G_H(6)  : A_H(10); //바뀜

A_M = INF > A_G(6) + G_M(7) ? A_G(6) + G_M(7) : A_M(INF); //바뀜

 

 

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

INF

8

INF

14

6

10

INF

INF

INF

INF

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

 

 

 

 

 

O

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

4. 최소 가중치들 중에 아직 방문하지 않으면서 제일 작은 가중치를 가진 정점 선별

 

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

INF

8

INF

14

6

10

INF

INF

INF

INF

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

 

 

 

 

 

O

 

 

 

 

 

 

 

위표를 기준으로 D 제일 작고, 방문하지 않았으므로 D 선택됐다.

 

5. 선별한 정점(D) 방문, 방문한 정점 주변에 인접한 정점들을 파악

6. 인접한 정점들중 시작점을 기준으로 해당 정점들까지의 최소 가중치 구해서 비교한뒤 빠르면 정리해놓은 최소 가중치를 수정, 느리면 그대로둠

(현재 기준점 까지의 최소가중치)+(인접한 정점까지의 가중치) < 현재 기록되어있는 최소 가중치

 

A_E = A_E(INF) > A_D(8) + D_E(10) ? A_D(8) + D_E(10) : A_E(INF); //바뀜

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

INF

8

18

14

6

10

INF

INF

INF

INF

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

 

 

O

 

 

O

 

 

 

 

 

 

 

 

 

 

 

 

 

7.최소 가중치들 중에 아직 방문하지 않으면서 제일 작은 가중치를 가진 정점 선별

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

INF

8

18

14

6

10

INF

INF

INF

INF

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

 

 

O

 

 

O

 

 

 

 

 

 

B 선택됐다.

 

8. 선별한 정점(B) 방문, 방문한 정점 주변에 인접한 정점들을 파악

9. 인접한 정점들중 시작점을 기준으로 해당 정점들까지의 최소 가중치 구해서 비교한뒤 빠르면 정리해놓은 최소 가중치를 수정, 느리면 그대로둠

(현재 기준점 까지의 최소가중치)+(인접한 정점까지의 가중치) < 현재 기록되어있는 최소 가중치

A_C = A_C(INF) > A_B(9) + B_C(8) ? A_B(9) + B_C(8) : A_C(INF); //바뀜

 

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

17

8

18

14

6

10

INF

INF

INF

INF

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

O

 

O

 

 

O

 

 

 

 

 

 

 

 

 

 

 

 

10. 최소 가중치들 중에 아직 방문하지 않으면서 제일 작은 가중치를 가진 정점 선별

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

17

8

18

14

6

10

INF

INF

INF

INF

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

O

 

O

 

 

O

 

 

 

 

 

 

H 선택됐다

 

11. 선별한 정점(H) 방문, 방문한 정점 주변에 인접한 정점들을 파악

12. 인접한 정점들중 시작점을 기준으로 해당 정점들까지의 최소 가중치 구해서 비교한뒤 빠르면 정리해놓은 최소 가중치를 수정, 느리면 그대로둠

(현재 기준점 까지의 최소가중치)+(인접한 정점까지의 가중치) < 현재 기록되어있는 최소 가중치

 

A_I = A_I(INF) > A_H(10) + H_I(10) ? A_H(10) + H_I(10) : A_I(INF); // 바뀜

 

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

17

8

18

14

6

10

20

INF

INF

INF

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

O

 

O

 

 

O

O

 

 

 

 

 

 

 

 

 

 

 

 

 

13. 최소 가중치들 중에 아직 방문하지 않으면서 제일 작은 가중치를 가진 정점 선별

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

17

8

18

14

6

10

20

INF

INF

INF

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

O

 

O

 

 

O

O

 

 

 

 

 

M 선택됐다

 

14. 선별한 정점(M) 방문, 방문한 정점 주변에 인접한 정점들을 파악

15. 인접한 정점들중 시작점을 기준으로 해당 정점들까지의 최소 가중치 구해서 비교한뒤 빠르면 정리해놓은 최소 가중치를 수정, 느리면 그대로둠

(현재 기준점 까지의 최소가중치)+(인접한 정점까지의 가중치) < 현재 기록되어있는 최소 가중치

 

A_I = A_I(20) > A_M(13) + M_I(13) ? A_M(13) + M_I(13) : A_I(20) // 그대로

 

A_L = A_L(INF) > A_M(13) + M_L(7) ? : A_M(13) + M_L(7) : A_L(INF) // 바뀜

 

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

17

8

18

14

6

10

20

INF

INF

20

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

O

 

O

 

 

O

O

 

 

 

 

O

 

 

 

 

 

 

 

16. 최소 가중치들 중에 아직 방문하지 않으면서 제일 작은 가중치를 가진 정점 선별

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

17

8

18

14

6

10

20

INF

INF

20

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

O

 

O

 

 

O

O

 

 

 

 

O

F 선택됐다

 

17. 선별한 정점(F) 방문, 방문한 정점 주변에 인접한 정점들을 파악

18. 인접한 정점들중 시작점을 기준으로 해당 정점들까지의 최소 가중치 구해서 비교한뒤 빠르면 정리해놓은 최소 가중치를 수정, 느리면 그대로둠

(현재 기준점 까지의 최소가중치)+(인접한 정점까지의 가중치) < 현재 기록되어있는 최소 가중치

 

A_E = A_E(18) > A_F(14) + F_E(7) ? A_F(14) +F_E(7) : A_E(18) // 그대로

 

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

17

8

18

14

6

10

20

INF

INF

20

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

O

 

O

 

O

O

O

 

 

 

 

O

 

 

 

 

 

 

 

19. 최소 가중치들 중에 아직 방문하지 않으면서 제일 작은 가중치를 가진 정점 선별

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

17

8

18

14

6

10

20

INF

INF

20

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

O

 

O

 

O

O

O

 

 

 

 

O

C 선택됐다.

 

20. 선별한 정점(C) 방문, 방문한 정점 주변에 인접한 정점들을 파악

21. 인접한 정점들중 시작점을 기준으로 해당 정점들까지의 최소 가중치 구해서 비교한뒤 빠르면 정리해놓은 최소 가중치를 수정, 느리면 그대로둠

(현재 기준점 까지의 최소가중치)+(인접한 정점까지의 가중치) < 현재 기록되어있는 최소 가중치

 

A_I = A_I(20) > A_C(17) + C_I(7) ? A_C(17) + C_I(7) : A_I(20) // 그대로

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

17

8

18

14

6

10

20

INF

INF

20

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

O

O

O

 

O

O

O

 

 

 

 

O

 

 

 

 

 

 

 

 

 

22. 최소 가중치들 중에 아직 방문하지 않으면서 제일 작은 가중치를 가진 정점 선별

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

17

8

18

14

6

10

20

INF

INF

20

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

O

O

O

 

O

O

O

 

 

 

 

O

E 선택됐다.

 

 

23. 선별한 정점(E) 방문, 방문한 정점 주변에 인접한 정점들을 파악

24. 인접한 정점들중 시작점을 기준으로 해당 정점들까지의 최소 가중치 구해서 비교한뒤 빠르면 정리해놓은 최소 가중치를 수정, 느리면 그대로둠

(현재 기준점 까지의 최소가중치)+(인접한 정점까지의 가중치) < 현재 기록되어있는 최소 가중치

 

A_J = A_J(INF) > A_E(18) + E_J(11) ? A_E(18) + E_J(11)  : A_J(INF) // 바뀜

 

 

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

17

8

18

14

6

10

20

29

INF

20

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

O

O

O

O

O

O

O

 

 

 

 

O

 

 

 

25.최소 가중치들 중에 아직 방문하지 않으면서 제일 작은 가중치를 가진 정점 선별

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

17

8

18

14

6

10

20

29

INF

20

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

O

O

O

O

O

O

O

 

 

 

 

O

I L 둘다 안방문 했으면서, 그중에서 제일 작은 가중치 20 동일하게 나타내고 있다, 이럴때는 for문과 배열을 사용한다는 것을 감안하여 순차적으로 I부터 방문한다

 

 

 

26.선별한 정점(I) 방문, 방문한 정점 주변에 인접한 정점들을 파악

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

O

O

O

O

O

O

O

O

 

 

 

O

 

 

27.인접한 정점들중 시작점을 기준으로 해당 정점들까지의 최소 가중치 구해서 비교한뒤 빠르면 정리해놓은 최소 가중치를 수정, 느리면 그대로둠

 

※인접하면서 아직 방문하지 않은 정점이 주변에 하나도 없으므로 과정이 생략된다(반복문 안에 조건문을 만족시키지 못하고 계속 continue 되어 결국 반복문이 끝나고 다음 순서, 최소 가중치 정점 선별로 넘어가 버린다.)

 

 

 

 

 

 

 

28.최소 가중치들 중에 아직 방문하지 않으면서 제일 작은 가중치를 가진 정점 선별

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

17

8

18

14

6

10

20

29

INF

20

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

O

O

O

O

O

O

O

O

 

 

 

O

L 선택됐다.

 

29. 선별한 정점(L) 방문, 방문한 정점 주변에 인접한 정점들을 파악

30. 인접한 정점들중 시작점을 기준으로 해당 정점들까지의 최소 가중치 구해서 비교한뒤 빠르면 정리해놓은 최소 가중치를 수정, 느리면 그대로둠

(현재 기준점 까지의 최소가중치)+(인접한 정점까지의 가중치) < 현재 기록되어있는 최소 가중치

 

A_K = A_K(INF) > A_L(20) + L_K(7) ? A_L(20) + L_K(7)  : A_K(INF) // 바뀜

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

17

8

18

14

6

10

20

29

27

20

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

O

O

O

O

O

O

O

O

 

O

 

O

 

 

 

 

 

 

31. 최소 가중치들 중에 아직 방문하지 않으면서 제일 작은 가중치를 가진 정점 선별

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

17

8

18

14

6

10

20

29

27

20

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

O

O

O

O

O

O

O

O

 

 

O

O

K 선택됐다.

 

 

32. 선별한 정점(K) 방문, 방문한 정점 주변에 인접한 정점들을 파악

33. 인접한 정점들중 시작점을 기준으로 해당 정점들까지의 최소 가중치 구해서 비교한뒤 빠르면 정리해놓은 최소 가중치를 수정, 느리면 그대로둠

(현재 기준점 까지의 최소가중치)+(인접한 정점까지의 가중치) < 현재 기록되어있는 최소 가중치

A_J = A_J(29) > A_K(27) + K_J(9) ? A_K(27) + K_J(9)  : A_J(29) // 그대로

 

 

 

 

 

 

 

34. 최소 가중치들 중에 아직 방문하지 않으면서 제일 작은 가중치를 가진 정점 선별

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

17

8

18

14

6

10

20

29

27

20

13

 

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

O

O

O

O

O

O

O

O

 

O

O

O

J 선택됐다.

 

35. 선별한 정점(J) 방문, 방문한 정점 주변에 인접한 정점들을 파악

정점

A

B

C

D

E

F

G

H

I

J

K

L

M

방문

O

O

O

O

O

O

O

O

O

O

O

O

O

 

36. 인접한 정점들중 시작점을 기준으로 해당 정점들까지의 최소 가중치 구해서 비교한뒤 빠르면 정리해놓은 최소 가중치를 수정, 느리면 그대로둠

※인접하면서 아직 방문하지 않은 정점이 주변에 하나도 없으므로 과정이 생략된다(반복문 안에 조건문을 만족시키지 못하고 계속 continue 되어 결국 반복문이 끝나고 다음 순서, 최소 가중치 정점 선별로 넘어가 버린다.)

 

 

 

 

37. 해당 그래프를 기준으로 여기까지 하면 11 방문, 즉 정확히 전체정점 개(12) - 1 만큼,  아래 과정을 반복하게 된다.

 

  1. 최소 가중치들 중에 아직 방문하지 않으면서 제일 작은 가중치를 가진 정점 선별
  2. 선별한 정점 방문, 방문한 정점 주변에 인접한 정점들을 파악
  3. 인접한 정점들중 시작점을 기준으로 해당 정점들까지의 최소 가중치 구해서 비교한뒤 빠르면 정리해놓은 최소 가중치를 수정, 느리면 그대로둠
    • (현재 기준점 까지의 최소가중치)+(인접한 정점까지의 가중치) < 현재 기록되어있는 최소 가중치

 

 

 

 

알고리즘이 종료 되면, 지금까지 초기화 시켰던 최소 가중치 정리 배열에는 시작점(A) 부터 각각 정점까지 가는데 드는 최소 비용을 정리해 놓게 된다.

경로

A_A

A_B

A_C

A_D

A_E

A_F

A_G

A_H

A_I

A_J

A_K

A_L

A_M

가중치

0

9

17

8

18

14

6

10

20

29

27

20

13

예를들면 A(시작점) 에서 정점 K 까지 간다고 했을때, A -> D -> E  -> J -> K 거쳐서 수도 있겠지만

가중치 크기 비교를 하면

A -> G -> M -> L -> K( A_G + G_M + M_L + L_K )  A -> D -> E  -> J -> K(A_D + D_E + E_J + J_K) 보다 작다,

 

빠르게 있다는 뜻이고, 이렇게 다양한 정점들 속에서 나올 있는 최소비용, 최단거리들을 기록해 놓은 것이 위의 표이고, 지금까지의 과정 Dijkstra 알고리즘을 통해서 구할 있는 것이다.

 

 

지하철 노선도 앱 최단 경로 탐색

반응형
반응형

깊이 우선 탐색(Depth First Search) _ 재귀호출

  • 맹목적으로 각 vertex를 탐색할 주로 사용

  • 더이상 나아가지 못할때 까지 깊이 탐색하면서 나아감

  • Binary Search Tree의 재귀호출로 순회하는 함수(InOrder, PreOrder, PostOrder)들이 대표적인 예가 있다
  • 스택(Stack) 또는 재귀 호출이 사용된다.

재귀 호출 DFS 알고리즘 순서

1.시작점으로 vertex를 인자로 DFS 함수 호출

2.해당 vertex를 방문했다는 사실을 기록

3.해당 vertex와 인접하고 방문하지 않은 vertex를 인자로 DFS 함수를 호출

2~3 과정이 모든 vertex들을 방문할때까지 되풀이 된다.

 

위 그래프의 인접행렬을 이차원배열로 표현한뒤, DFS또한 구현하여 실행해봤다.

 

 

코드

constexpr int VERTEX_COUNT = 8;
constexpr int adj[VERTEX_COUNT][VERTEX_COUNT] =
{
	{0, 1, 1, 0, 0, 0, 0, 0}, //v0  : v1, v2
	{1, 0, 0, 1, 1, 0, 0, 0}, //v1  : v0, v3, v4
	{1, 0, 0, 0, 0, 1, 1, 0}, //v2  : v0, v5, v6
 	{0, 1, 0, 0, 0, 0, 0, 1}, //v3  : v1, v7
	{0, 1, 0, 0, 0, 0, 0, 1}, //v4  : v1, v7
	{0, 0, 1, 0, 0, 0, 0, 1}, //v5  : v2, v7
	{0, 0, 1, 0, 0, 0, 0, 1}, //v6  : v2, v7
	{0, 0, 0, 1, 1, 1, 1, 0}  //v7  : v3, v4, v5, v6
};

bool visited[VERTEX_COUNT]; //방문기록

void DFS_Recursive(int _start)
{
	visited[_start] = true; //방문
	printf("%d 방문\n", _start);
	for (int i = 0; i < VERTEX_COUNT; i++)
	{
		if (adj[_start][i] == 1 && !visited[i])//인접했다 && 방문안했다 
		{
			DFS_Recursive(i); //재귀호출, 인접한 vertex를 인자로 대입
		}
	}
}

int main()
{
	DFS_Recursive(0); 
	return 0;
}

실행결과

빨간색 화살표는 재귀호출이 시작되는것, 노란색은 재귀호출이 끝나고 원래 호출했던 함수로 돌아가는것(rewind)

실행결과를 보면 화살표 번호 순서대로 방문하는 것을 알 수 있다.

이과정을 자세히 들여다보면 처음 시작은 0부터 시작하므로 0을 인자로 넣어서 V0을 방문 V0에서 인접하며, 방문하지 않은 V1발견, V1을 인자로 재귀호출을 시작하게 된다. 아래 순서 번호는 곧 위 그림의 화살표 번호과 같다.

  1. V1을 방문, V1에서 인접하며, 방문하지 않은 V3발견, V3을 인자로 재귀호출                                        현재 누적 방문 : V0, V1                                                                                                             

  2. V3을 방문, V3에서 인접하며, 방문하지 않은 V7발견, V7을 인자로 재귀호출                                                        현재 누적 방문 : V0, V1, V3                                                                                                                         

  3. V7을 방문, V7에서 인접하며, 방문하지 않은 V4발견, V4을 인자로 재귀호출                                    현재 누적 방문 : V0, V1, V3, V7                                                                                                  
  4. V4을 방문, V4에서 인접하며, 방문하지 않은 vertex가 없으므로 재귀호출 하지 않고 함수가 끝남          현재 누적 방문 : V0, V1, V3, V7, V4                                                                                           
  5. V7을 인자로 가졌던 함수로 돌아감(rewind), V7에서 인접하며 방문하지 않은 V5발견, V5을 인자로 재귀호출                                                                                                                           현재 누적 방문 : V0, V1, V3, V7, V4                                                                                                                                                                                                                                                                                                                                                                     
  6. V5을 방문, V5에서 인접하며, 방문하지 않은 V2발견, V2을 인자로 재귀호출                                     현재 누적 방문 : V0, V1, V3, V7, V4, V5                                                                                         
  7. V2을 방문, V2에서 인접하며, 방문하지 않은 V6발견, V6을 인자로 재귀호출                                    현재 누적 방문 : V0, V1, V3, V7, V4, V5, V2                                                                              
  8. V6을 방문, V6에서 인접하며, 방문하지 않은 vertex가 없으므로 재귀호출 하지 않고 함수가 끝남 이때부터는 모두 방문했으므로 rewind 되는 것만 남음                                                                  현재 누적 방문 : (모두 방문 완료)V0, V1, V3, V7, V4, V5, V2, V6                                                                                                                                                                                      
  9. V2을 인자로 가졌던 함수로 돌아감, 모두 방문했으므로, 재귀호출 하지 않고 함수가 끝남
  10. V5을 인자로 가졌던 함수로 돌아감, 모두 방문했으므로, 재귀호출 하지 않고 함수가 끝남
  11. V7을 인자로 가졌던 함수로 돌아감, 모두 방문했으므로, 재귀호출 하지 않고 함수가 끝남
  12. V3을 인자로 가졌던 함수로 돌아감, 모두 방문했으므로, 재귀호출 하지 않고 함수가 끝남
  13. V1을 인자로 가졌던 함수로 돌아감, 모두 방문했으므로, 재귀호출 하지 않고 함수가 끝남
  14. V0을 인자로 가졌던 함수로 돌아감(처음 호출했던 함수), 모두 방문했으므로, 재귀호출 하지 않고 함수가 끝남

 

 

반응형

+ Recent posts