1504번: 특정한 최단 경로
첫째 줄에 정점의 개수 N과 간선의 개수 E가 주어진다. (2 ≤ N ≤ 800, 0 ≤ E ≤ 200,000) 둘째 줄부터 E개의 줄에 걸쳐서 세 개의 정수 a, b, c가 주어지는데, a번 정점에서 b번 정점까지 양방향 길이 존
www.acmicpc.net
- 해당 문제는 최단 경로 문제에서 특정한 정점을 무조건 지나야 한다는 조건을 추가한 문제이다.
- 물론, 특정한 정점을 지나갈 때에도 최단 거리의 경로를 지날 수 있도록 계산해야 한다.
- 시작점 -> 특정한 점_1 -> 특정한 점_2 -> 도착점의 최단 경로 계산을 나누어야 한다.
시작점 -> 특정한 점_1
특정한 점_1 -> 특정한 점_2
특정한 점_2 -> 도착점
과
시작점 -> 특정한 점_2
특정한 점_2 -> 특정한 점_1
특정한 점_1 -> 도착점
- 위 2개의 계산 중 작은 값을 결과값으로 사용하면 해결된다.
더보기
#include <iostream>
#include <limits.h>
#include <queue>
#include <vector>
//max size
#define N_MAX_SIZE 800
#define E_MAX_SIZE 200000
#define C_MAX_SIZE 1000
#define MUST_VERTEX_SIZE 2
//debug
#define debug_m 0
// struct
struct NODE
{
NODE()
: to(0)
, dist(INT_MAX)
{
}
int to;
int dist;
};
struct WEIGHT
{
WEIGHT()
: v(0)
, w(INT_MAX)
{
}
bool operator()(WEIGHT a, WEIGHT b)
{
if (a.w > b.w)
return true;
else
return false;
}
int v, w;
};
// global
int distArr[N_MAX_SIZE + 1];
// method
int CalcDijkstra(std::vector<std::vector<NODE>>& src, const int mustVertex[], const int NCnt, const int ECnt);
int main()
{
/// init
std::ios::sync_with_stdio(false);
for (int i = 0; i < N_MAX_SIZE + 1; i++)
{
distArr[i] = INT_MAX;
}
/// input
int N = 0; // 정점의 개수
int E = 0; // 간선의 개수
(void)scanf("%d %d", &N, &E);
std::vector<std::vector<NODE>> inputLists;
inputLists.resize(N + 1);
for (int e = 0; e < E; e++)
{
NODE input;
int from = 0;
(void)scanf("%d %d %d", &from, &input.to, &input.dist);
inputLists[from].push_back(input);
// 양방향
NODE another;
another.to = from;
another.dist = input.dist;
inputLists[input.to].push_back(another);
}
/// 반드시 거쳐야 하는 두 개의 서로 다른 정점
int mustVertex[MUST_VERTEX_SIZE] = { 0, };
(void)scanf("%d %d", &mustVertex[0], &mustVertex[1]);
/// Dijkstra Function
const int answer_1 = CalcDijkstra(inputLists, mustVertex, N, E);
int temp = mustVertex[0];
mustVertex[0] = mustVertex[1];
mustVertex[1] = temp;
const int answer_2 = CalcDijkstra(inputLists, mustVertex, N, E);
const int finalAns = answer_1 < answer_2 ? answer_1 : answer_2;
/// print answer
if ( INT_MAX == distArr[N] || INT_MAX == finalAns)
printf("-1\n");
else
printf("%d\n", finalAns);
return 0;
}
/// Method
int CalcDijkstra(std::vector<std::vector<NODE>>& src, const int mustVertex[], const int NCnt, const int ECnt)
{
#if debug_m
printf("\n-----[%s] ----- \n", __FUNCTION__);
#endif
int retValue = 0;
/*
* 1 -> mustVertex[0]
* mustVertex[0] -> mustVertex[1]
* mustVertex[1] -> NCnt
*/
std::vector<int> startList;
startList.push_back(1);
startList.push_back(mustVertex[0]);
startList.push_back(mustVertex[1]);
startList.push_back(NCnt); // end vertex
for (int s = 0; s < startList.size() - 1; s++)
{
std::priority_queue<WEIGHT, std::vector<WEIGHT>, WEIGHT> priQue;
int startV = startList[s];
int endV = startList[s + 1];
#if debug_m
printf("--startV : %d, endV : %d \n", startV, endV);
#endif
// init
for (int i = 0; i <= NCnt; i++)
{
distArr[i] = INT_MAX;
}
for (int i = 1; i <= NCnt; i++)
{
WEIGHT vertex;
vertex.v = i;
if (i == startV)
{
vertex.w = 0;
distArr[i] = 0;
}
priQue.push(vertex);
}
// calc
while (!priQue.empty())
{
WEIGHT curVertex = priQue.top();
priQue.pop();
if (INT_MAX == curVertex.w)
break;
std::vector<NODE> curVertexInfo = src[curVertex.v];
std::vector<NODE>::const_iterator iter;
for (iter = curVertexInfo.begin(); iter != curVertexInfo.end(); ++iter)
{
NODE node = *iter;
if (distArr[node.to] > (node.dist + distArr[curVertex.v]))
{
distArr[node.to] = node.dist + distArr[curVertex.v];
WEIGHT pushInfo;
pushInfo.v = node.to;
pushInfo.w = distArr[node.to];
priQue.push(pushInfo);
}
}
}
retValue += distArr[endV];
#if debug_m
printf(">> distArr[endV] : %d, retValue : %d \n", distArr[endV], retValue);
#endif
}
return retValue;
}
'Coding Problem > 백준' 카테고리의 다른 글
[백준] 1463 - 1로 만들기 (0) | 2021.01.19 |
---|---|
[백준] 9370 - 미확인 도착지 (0) | 2021.01.14 |
[백준] 1753 - 최단 경로 (0) | 2021.01.03 |
[백준] 2206 - 벽 부수고 이동하기 (0) | 2020.12.08 |
[백준] 1697 - 숨박꼭질 (0) | 2020.12.07 |