이야기박스

c) 가중치 / 다익스트라 응용, 최단거리 찾기 + 개수 찾기 본문

Programming Language/c, c++

c) 가중치 / 다익스트라 응용, 최단거리 찾기 + 개수 찾기

박스님 2017. 3. 17. 19:41
반응형

다익스트라 어렵죠 ㅎㅎ.

코드 보고 참고하셨으면 좋겠네요.


인접리스트를 이용한 다익스트라 입니다.

물론 가중치도 존재합니다!


전체 그래프의 모형은 다음과 같습니다.




그러면 소스를 보여드리도록 하겠습니다 ^^



#include 
#include

#define	INFINITE 9999	// 거리의 초기값
#define	NUM_VERTICES 6	// 정점의 개수

// 인접리스트 구조체
typedef struct Adjacency
{
	struct Adjacency *link;		// 연결
	int vertex;					// 정점
	int weight;					// 무게
}Adjacency;

// 인접 리스트
Adjacency *Graph_list[NUM_VERTICES];

void initGraph();
void insertEdge(int, int, int);
void DijkstraShortestPathsSingleTargetCount(int, int);

void main()
{
	char start, end;

	// 그래프 생성.
	initGraph();	

	// 시점, 종점 입력
	printf("시점 >> ");
	scanf("%c", &start);
	getchar();
	printf("종점 >> ");
	scanf("%c", &end);

	DijkstraShortestPathsSingleTargetCount(start-'A', end-'A'); // 다익스트라 알고리즘 실행
}

// 그래프를 초기화해주는 함수 - 간선 수만큼 연결해줘야 한다.
void initGraph() {
	// A의 연결점 추가
	insertEdge(0, 1, 8);	// A-B
	insertEdge(0, 2, 1);	// A-C
	insertEdge(0, 3, 4);	// A-D

	// B의 연결점 추가
	insertEdge(1, 2, 7);	// B-C
	insertEdge(1, 4, 4);	// B-E
	
	// C의 연결점 추가 
	insertEdge(2, 3, 5);	// C-D
	insertEdge(2, 4, 3);	// C-E
	insertEdge(2, 5, 9);	// C-F

	// D의 연결점 추가
	insertEdge(3, 5, 4);	// D-F

	// E의 연결점 추가 - 이미 위에서 완료
	// F의 연결점 추가 - 이미 위에서 완료
}

void insertEdge(int start, int end, int weight)
{
	Adjacency *node;	// 연결을 위한 노드

	// 양방향으로 연결을 해줘야 한다.
	node = (Adjacency *)malloc(sizeof(Adjacency));
	node->vertex = end;
	node->weight = weight;
	node->link = Graph_list[start];
	Graph_list[start] = node;

	// 반대쪽에서도 연결
	node = (Adjacency*)malloc(sizeof(Adjacency));
	node->vertex = start;
	node->weight = weight;
	node->link = Graph_list[end];
	Graph_list[end] = node;
}

void DijkstraShortestPathsSingleTargetCount(int start, int end)
{
	int distance[NUM_VERTICES];		// 거리
	int	pathcnt[NUM_VERTICES];		// 경로 수
	int check[NUM_VERTICES];		// 가방 안에 있는지 여부
	Adjacency *tmp;					// 최근에 들어온 정점을 저장하기 위한 구조체 포인터
	int cycle, min, now, i;			// cycle : 작업 횟수, 
									// min = 최단거리를 위한 비교값, 
									// now : 최근에 들어온 정점

	// 초기화 과정
	for (i = 0; i < NUM_VERTICES; i++)
	{
		distance[i] = INFINITE;		// 거리를 무한으로 초기화
		pathcnt[i] = 0;				// 경로수를 0으로 초기화
		check[i] = 0;				// PQ에 있는지 없는지 여부 ( PQ에 들어있다면 0 )
	}
	distance[start] = 0;			// 초기 start 설정 - 자신까지의 거리는 0
	cycle = 0;

	while (cycle < NUM_VERTICES - 1)		// 모든 정점에 대해 하기 위해서
	{
		min = INFINITE;		// 최소값 무한으로 초기화
		for (i = 0; i < NUM_VERTICES; i++)
			if (distance[i] < min && !check[i])		// 가방 밖의 정점 중 거리가 최소인 정점으로부터 시작
			{
				min = distance[i];
				now = i;	// 가방에 넣을 정점 위치
			}

		check[now] = 1;			// 가방 안에 넣기
		tmp = Graph_list[now];	// 가방에 새로 들어온 정점의 구조체 포인터

		while(tmp != NULL)
		{	
			if (!check[tmp->vertex])	// 가방 밖의 정점이라면
			{
				// 수행한 거리 = 기존 최단거리 -- 다른 경로를 통한 같은 최단거리
				if (min + tmp->weight == distance[tmp->vertex])	
					pathcnt[tmp->vertex] += pathcnt[now];		// 최단경로 개수 증가
				
				//  수행한 거리 < 기존 최단거리 --> 간선 완화
				if (min + tmp->weight < distance[tmp->vertex])	
				{
					distance[tmp->vertex] = min + tmp->weight;	// 최단거리 갱신
					if(now==start ) pathcnt[tmp->vertex] = 1;				// 만약 시작점에서의 연결점이라면 경로수 1
					else			pathcnt[tmp->vertex] = pathcnt[now];	// 그 이외에는 부모위치의 경로수
				}
			}	// if
		tmp = tmp->link;	// 다음 인접 정점, 간선 검사
		}	// while

		cycle++;
		if (now == end) break;		// 현재 정점이 도착 정점과 같다면 종료
	}	// while

	printf("%c, %c 최단거리 = %d, 최단경로 수 = %d\n", start + 'A', end + 'A', distance[end], pathcnt[end]); // 결과물 출력
}




실행 화면 입니다.


A -> C의 경우입니다.



D -> E의 경우입니다.



정말 고생하면서 짠 기억이 있네요 ㅎㅎ

모두에게 도움이 됬길 바라면서!


더 좋은 내용으로 찾아 뵙겠습니다.

반응형

'Programming Language > c, c++' 카테고리의 다른 글

c++) 정렬 알고리즘 종합 정리  (0) 2017.10.22
C) 하노이의 탑  (0) 2017.03.27
c) Heap 정렬을 해보자  (0) 2017.03.17
c++) 로또 번호 뽑기  (0) 2017.03.17
c, c++) 진행 방식  (0) 2017.03.17