[백준] 1753번 최단 경로 (= shortest path) - 재우스 프로그래밍 (C 언어)
2021. 2. 28. 21:04ㆍ백준
문제 링크 :www.acmicpc.net/problem/1753
알고리즘 : 우선순위 큐zeus-programming.tistory.com/65
우선순위 큐에서 가중치가 가장 낮은 노드를 최상위 부모 노드로 저장하는 이유는
출발 정점 K로부터 현재까지 계산한 값 중 가장 가까운 정점까지의 가중치는 다른 경우의 수에 의해 갱신될 수 없기 때문에
가중치가 가장 적은 정점과 그 가중치를 기준으로 다른 정점까지의 거리를 갱신하기 때문입니다.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAX_PQ_SIZE 300001
#define INF 200001
//입력값을 저장할 Node
typedef struct _Node {
char weight;
int vertex;
} Node;
typedef struct _vector {
Node *mem;
int memSize;
int back;
} vector;
//시작 정점 K로부터 연결된 정점(vertex)과 그 가중치(weight)가 저장된 priorityQueue의 Data
typedef struct _Data {
int weight;
int vertex;
} Data;
typedef struct _priority_queue {
Data mem[MAX_PQ_SIZE];
int back;
} priority_queue;
int V;
//입력값 간선이 5 1 2 라면 vec[5]의 mem[vec[5].back]에
//vertex = 1, weight = 2인 노드를 추가한다
int *result; //시작 정점 K로부터 연결된 정점 1이 가중치 2로 연결되어있다면 result[1] = 2 저장
vector *vec;
priority_queue *pq;
void initData(Data *);
void initPQ(priority_queue *);
bool empty(priority_queue *);
void pop(priority_queue *);
void push(priority_queue *, Data);
size_t size(priority_queue *);
Data top(priority_queue *);
void swapData(Data *, Data *);
void initNode(Node *);
void initVEC(vector *);
void vectorFull(vector *);
void push_back(vector *, Node);
size_t sizeV(vector *);
void Dijkstra(int);
void initResult(int);
int main(void)
{
//정점의 개수 V, 간선의 개수 E, 시작 정점의 번호 K
int E = 0, K = 0;
//입력 받는 간선의 출발 정점 start, 도착 정점 end, 간선의 가중치 weight
int start = 0;
pq = (priority_queue *)malloc(sizeof(priority_queue));
Node tmpNode;
scanf("%d %d", &V, &E);
scanf("%d", &K);
//result 메모리 할당 및 초기화
vec = (vector *)malloc(sizeof(vector) * (V + 1));
result = (int *)malloc(sizeof(int) * (V + 1));
for (int i = 0; i < V + 1; i++)
initVEC(&vec[i]);
initResult(V);
//입력 받을 E개의 간선 vector에 저장
for (int i = 0; i < E; i++) {
scanf("%d %d %hhd", &start, &tmpNode.vertex, &tmpNode.weight);
push_back(&vec[start], tmpNode);
}
result[K] = 0; //자기 자신으로 가는 가중치는 0 저장
Dijkstra(K);
for (int i = 1; i <= V; i++) {
if (result[i] != INF)
printf("%d\n", result[i]);
else
printf("INF\n");
}
free(vec);
free(pq);
free(result);
return 0;
}
void initData(Data *data)
{
data->weight = 0;
data->vertex = 0;
return;
}
void initPQ(priority_queue *pq)
{
for (int i = 0; i < MAX_PQ_SIZE; i++) { initData(&pq->mem[i]); }
pq->back = 0;
return;
}
bool empty(priority_queue *pq)
{
if (!pq->back) { return true; }
else { return false; }
}
void pop(priority_queue *pq)
{
if (empty(pq)) { return; }
pq->mem[1] = pq->mem[pq->back];
initData(&pq->mem[pq->back--]);
if (empty(pq)) { return; }
int parent = 1;
int child = parent * 2;
int pqSize = (int)size(pq);
while (child <= pqSize) {
if (child + 1 <= pqSize && pq->mem[child].weight > pq->mem[child + 1].weight) { child++; }
if (pq->mem[parent].weight > pq->mem[child].weight) {
swapData(&pq->mem[parent], &pq->mem[child]);
parent = child;
child = parent * 2;
}
else { break; }
}
return;
}
void push(priority_queue *pq, Data data)
{
pq->mem[++pq->back] = data;
if ((int)size(pq) == 1) { return; }
int child = pq->back;
int parent = child / 2;
while (child > 1) {
if (pq->mem[parent].weight > pq->mem[child].weight) {
swapData(&pq->mem[parent], &pq->mem[child]);
child = parent;
parent = child / 2;
}
else { break; }
}
return;
}
size_t size(priority_queue *pq) { return (size_t)pq->back; }
Data top(priority_queue *pq) { return pq->mem[1]; }
void swapData(Data *pData, Data *cData)
{
Data temp;
initData(&temp);
temp = *pData;
*pData = *cData;
*cData = temp;
return;
}
void initNode(Node *node)
{
node->weight = 0;
node->vertex = 0;
return;
}
void initVEC(vector *vec)
{
vec->mem = (Node *)malloc(sizeof(Node) * 10);
for (int i = 0; i < 10; i++) { initNode(&vec->mem[i]); }
vec->memSize = 10;
vec->back = 0;
return;
}
void vectorFull(vector *vec)
{
vec->memSize *= 2;
vec->mem = (Node *)realloc(vec->mem, sizeof(Node) * (vec->memSize));
for (int i = vec->memSize / 2; i < vec->memSize; i++) { initNode(&vec->mem[i]); }
return;
}
void push_back(vector *vec, Node node)
{
if (vec->back == vec->memSize)
vectorFull(vec);
vec->mem[vec->back++] = node;
return;
}
size_t sizeV(vector *vec) { return (size_t)vec->back; }
void Dijkstra(int K)
{
vector *tmpVec;
Data tmpData;
tmpData.vertex = K;
tmpData.weight = result[K];
push(pq, tmpData); //먼저 자기 자신으로 가는 것을 검사한다
while (!empty(pq)) {
//priorityQueue에서 시작 정점 K로부터 가장 가까운 정점과 가중치 가져옴
int curV = top(pq).vertex;
int curW = top(pq).weight;
pop(pq);
//예를 들어 vector[1]에 vertex 2로 가는 경로의 가중치가 2, 3, 4인 경우가 있다면
//result[2]의 값이 INF이므로 priorityQueue 안에 (2, 2), (2, 3), (2, 4)가
//전부 들어가지만 한 번 (2, 2)인 경우를 계산함으로써 result[2]값이 갱신된다면
//큐 안의 (2, 3)과 (2, 4)는 계산하지 않고 넘어가게 해준다.
if (result[curV] < curW) { continue; }
tmpVec = &vec[curV];
//정점curV 로부터 연결된 모든 정점들을 검사한다.
for (int i = 0; i < (int)sizeV(tmpVec); i++) {
if (result[tmpVec->mem[i].vertex] > curW + tmpVec->mem[i].weight) {
result[tmpVec->mem[i].vertex] = curW + tmpVec->mem[i].weight;
tmpData.vertex = tmpVec->mem[i].vertex;
tmpData.weight = result[tmpData.vertex];
push(pq, tmpData);
}
}
}
return;
}
void initResult(int V)
{
for (int i = 1; i <= V; i++)
result[i] = INF;
return;
}
'백준' 카테고리의 다른 글
[백준] 2623번 음악프로그램 (= music program) - 재우스 프로그래밍 (C 언어) (0) | 2021.03.01 |
---|---|
[백준] 2529번 부등호 (= inequality sign) - 재우스 프로그래밍 (C 언어) (0) | 2021.02.28 |
[백준] 11279번 최대 힙 (= maximum heap) - 재우스 프로그래밍 (C 언어) (0) | 2021.02.22 |
[백준] 1927번 최소 힙 (= minimal heap) - 재우스 프로그래밍 (C 언어) (0) | 2021.02.22 |
[백준] 12789번 도키도키 간식드리미 (= dokidoki snack helper) - 재우스 프로그래밍 (C 언어) (0) | 2021.02.21 |