등산
https://www.acmicpc.net/problem/16681
| 시간 제한 | 메모리 제한 | 제출 | 정답 | 맞힌 사람 | 정답 비율 |
|---|---|---|---|---|---|
| 1 초 | 256 MB | 3180 | 827 | 568 | 22.576% |
문제
주환이는 요즘 등산에 빠졌다. 주환이는 등산을 위해 지도를 가지고 있는데,
그 지도에는 각 지점의 높이와 갈 수 있는 다른 지점까지의 거리가 표시되어 있다.
주환이는 아침에 집에서 출발하여 등산을 갔다가, 오후 수업을 듣기 위해 고려대학교로 돌아와야 한다.
1. 주환이는 지도의 임의의 지점을 골라, 그 지점을 목표로 정한다. 집 또는 고려대학교는 목표로 선택할 수 없다.
2. 주환이가 집에서 정한 목표에 도달할 때 까지는 항상 높이가 증가하는 방향으로만 이동해야 한다.
3. 주환이가 정한 목표에 도달한 후, 고려대학교로 갈 때에는 항상 높이가 감소하는 방향으로만 이동해야 한다.
4. 주환이는 거리 1을 움직일 때 마다 D 의 체력이 소모된다.
5. 주환이는 정한 목표에 도달하면 높이 1당 E 의 성취감을 얻는다. 즉 높이가 h인 목표에 도달하면 hE의 성취감을 얻는다.
주환이는 이 등산의 가치를 (얻은 성취감) – (소모한 체력) 으로 계산하기로 하였다.
주환이를 위해 가치가 가장 높은 등산 경로를 선택해주자.
입력
첫 번째 줄에 지도에 표시된 지점의 개수, 지점을 잇는 경로의 개수, 주환이의 거리 비례 체력 소모량,
높이 비례 성취감 획득량을 나타내는 정수 N, M, D, E가 공백을 사이에 두고 주어진다.
(2 ≤ N ≤ 100,000, 1 ≤ M ≤ 200,000, 1 ≤ D ≤ 100, 1 ≤ E ≤ 100)
두 번째 줄에 N개의 정수 h1, … ,hN이 공백으로 구분되어 주어진다. hi는 i 번째 지점의 높이를 의미한다.
(1 ≤ hi ≤ 1,000,000, 1 ≤ i ≤ N)
세 번째 줄부터 M개의 줄에 걸쳐 세 정수 a, b, n이 공백으로 구분되어 주어진다.
이는 a번 지점과 b번 지점을 잇는 거리 n의 양방향 경로가 있음을 의미한다. (1 ≤ a, b ≤ N, 1 ≤ n ≤ 100,000)
어떤 지점에서 다른 지점으로 가는 경로가 여러 개 있을 수도 있으며 (등산로는 여러 개가 있을 수 있다),
한 지점에서 출발해 그 지점으로 돌아가는 경로가 있을 수도 있다 (쉼터에서 몇 바퀴 돌며 쉴 수도 있다).
주환이의 집은 1번 지점에 위치하고, 고려대학교는 N번 지점에 위치하며 주환이의 집과 고려대학교의 높이는 1임이 보장된다.
출력
첫 번째 줄에 주환이가 얻을 수 있는 가치의 최댓값을 출력한다.
만약 조건을 만족하는 등산 경로를 선택할 수 없다면, “Impossible“을 쌍따옴표를 제외하고 출력한다.
답이 음수일 수 있음에 유의하여라.
예제 입력 1
8 13 4 9 1 4 7 3 10 2 15 1 1 2 3 3 4 2 5 6 6 7 8 2 2 3 4 6 7 2 3 6 1 4 8 3 5 1 6 8 3 5 2 5 4 4 6 3 5 3 8
예제 출력 1
15
예제 입력 2
3 2 1 1 1 1 1 1 2 5 2 3 5
예제 출력 2
Impossible
출처
University > 고려대학교 > 2018 고려대학교 프로그래밍 경시대회 (KCPC) > Advanced Div. C번
University > 고려대학교 > 2018 고려대학교 프로그래밍 경시대회 (KCPC) > Intermediate Div. E번
- 문제를 만든 사람: oree2113
알고리즘 분류

통과된 코드
자료형 long long 필수!
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
constexpr int MAXN = 100001;
constexpr long long int INF = INT64_MAX;
constexpr long long int uINF = INT64_MIN;
///*
//각 노드에 연결되어 있는 노드에 대한 정보를 담는 벡터
//a번 노드에서 b번 노드로 가는 비용이 c라는 의미
//graph[a].push_back((make_pair(B, C));
//*/
vector<pair<int, int>> upGraph[MAXN];
vector<pair<int, int>> downGraph[MAXN];
// Dijkstra 알고리즘에 사용할 우선순위 큐
priority_queue<pair<long long int, int>> myPQ;
// N 지점의 개수, M 지점을 잇는 경로의 개수
// D 주환이의 거리 비례 체력 소모량, E 높이 비례 성취감 획득량
int N, M, D, E;
// 각 지점의 높이를 저장하는 배열
int hArr[MAXN];
// 등산을 하는데 필요한 배열 (집 -> 산)
long long int upArr[MAXN];
long long int temp = 0;
// 결과를 저장
long long int result = uINF;
// 하산을 하는데 필요한 배열 (산 -> 고려대)
long long int downArr[MAXN];
// V1,2 지점, d : 지점 사이의 거리
int V1, V2, d;
void Dijkstra(int start, long long int arr[], vector<pair<int, int>> graph[])
{
// 임시배열 초기화
for (int i = 1; i <= N; i++) arr[i] = INF;
// 우선순위 큐에 삽입.
myPQ.push({ 0, start }); // < first : 거리 , second : 노드 인덱스 >
arr[start] = 0;
while (!myPQ.empty()) {
// -를 붙이는 이유는 우선순위 큐를 이용하여 정렬하기 위함이다.
// (최소힙으로 구현)
long long int nCost = -myPQ.top().first;
int now = myPQ.top().second;
myPQ.pop();
// 이미 담겨 있는 것보다 거리가 크면 넘어간다.
if (arr[now] < nCost) continue;
// 해당 노드에서 연결된 모든 경로를 확인
for (int i = 0; i < graph[now].size(); i++) {
// disSum = 임시 노드 + 현재 노드에서 i로가는 비용
long long int disSum = nCost + graph[now][i].second;
// 비용이 더 작다면 최단경로 테이블 값을 갱신.
if (disSum < arr[graph[now][i].first]) {
// 임시 노드 업데이트
arr[graph[now][i].first] = disSum;
// 우선순위 큐에 (거리, 노드 인덱스) 푸시
myPQ.push(make_pair(-disSum, graph[now][i].first));
}
}
}
}
int main()
{
ios_base::sync_with_stdio(false); // scanf와 동기화를 비활성화
// cin.tie(null); 코드는 cin과 cout의 묶음을 풀어줍니다.
cin.tie(NULL);
cout.tie(NULL);
// 문제의 조건들을 입력 받는다.
cin >> N >> M >> D >> E;
// 각 지점의 높이를 입력 받는다.
for (int i = 1; i <= N; i++) cin >> hArr[i];
// 경로를 입력 받는다.
for (int i = 0; i < M; i++) {
cin >> V1 >> V2 >> d;
// 높이가 같을 경우에는 생각하지 않는다.
if (hArr[V1] > hArr[V2]) { // V1의 높이가 더 높을 경우
upGraph[V2].push_back(make_pair(V1, d));
downGraph[V2].push_back(make_pair(V1, d));
}
else if (hArr[V1] < hArr[V2]) { // V1의 높이가 더 낮은 경우
upGraph[V1].push_back(make_pair(V2, d));
downGraph[V1].push_back(make_pair(V2, d));
}
}
Dijkstra(1, upArr, upGraph);
Dijkstra(N, downArr, downGraph);
for (int i = 1; i <= N; i++) {
if (upArr[i] == INF || downArr[i] == INF) continue;
temp = upArr[i] + downArr[i];
result = max(result, hArr[i] * E - temp * D);
}
if (result == uINF) cout << "Impossible";
else cout << result;
return 0;
}
최악의 경우 예를 들어 N = 100,000 / M = 200,000 / hi = i / 모든 경로 거리 1 / D = 1 / E = 100 이런 식이면
int 를 사용하면 터진다. ㅠㅠ
long long int 로 바꾸어주자
로직 문제로 오인해서 많이 틀렸다.


![백준 9251번 (LCS, C++) [BAEKJOON]](https://lycos7560.com/wp-content/uploads/boj-og.png)
![백준 1389번 (케빈 베이컨의 6단계 법칙, C++) [BAEKJOON]](https://lycos7560.com/wp-content/uploads/2022/10/boj-og-1-2048x1070-1-1024x535.png)