일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- parametric search
- 최장길이바이토닉수열
- disjoint set
- boj 1464
- 그래프이론
- 패스트캠퍼스
- 최장증가수열
- Lis
- 2493 백준
- 이분탐색
- 그래프 탐색
- 깊이 우선 탐색
- 구현
- 1939백준
- 결정 문제
- 분할정복
- 백준 1464
- 백준 뒤집기 3
- bfs
- 그래프 이론
- 재귀
- union find
- 그래프탐색
- 이분 탐색
- 결정문제
- 비트마스킹
- 브루트포스
- 뒤집기 3
- DP
- 서로소 집합
- Today
- Total
알고리즘 문제풀이
[BOJ] 5214번 - 환승 본문
백준 5214번 - 환승
시간제한 | 메모리 제한 | 제출 | 정답 | 맞은 사람 | 정답 비율 |
---|---|---|---|---|---|
2초 | 256MB | 7552 | 1928 | 1316 | 26.320% |
문제
아주 먼 미래에 사람들이 가장 많이 사용하는 대중교통은 하이퍼튜브이다. 하이퍼튜브 하나는 역 K개를 서로 연결한다. 1번역에서 N번역으로 가는데 방문하는 최소 역의 수는 몇 개일까?
입력
첫째 줄에 역의 수 N과 한 하이퍼튜브가 서로 연결하는 역의 개수 K, 하이퍼튜브의 개수 M이 주어진다. (1 ≤ N ≤ 100,000, 1 ≤ K, M ≤ 1000)
다음 M개 줄에는 하이퍼튜브의 정보가 한 줄에 하나씩 주어진다. 총 K개 숫자가 주어지며, 이 숫자는 그 하이퍼튜브가 서로 연결하는 역의 번호이다.
출력
첫째 줄에 1번역에서 N번역으로 가는데 방문하는 역의 개수의 최솟값을 출력한다. 만약, 갈 수 없다면 -1을 출력한다.
예제 입력1
9 3 5
1 2 3
1 4 5
3 6 7
5 6 7
6 8 9
예제 출력1
4
출처
알고리즘 분류
- 그래프 이론
- 그래프 탐색
- 너비 우선 탐색
접근 방법
초기 접근(MLE)
하나의 하이퍼튜브에 포함된 모든 노드들을 mesh-topology로 재구성하는 방법은 어떨까?
최악의 경우, N개의 노드를 Fully-connected-mesh topology로 구성하는 방법은 N(N-1)/2 의 공간 복잡도가 필요하므로 256MB내에는 해결이 불가능하다는 것을 알 수 있다.
개선책
문제의 요구 사항에 따라, 하나의 노드는 반드시 1개 이상의 Hypertube에 연결되는 것을 확인할 수 있다. 또한 하나의 노드는 다른 노드와 직접적으로 연결되지 못한다. 하나의 노드가 다른 노드와 연결되기 위해서는 반드시 1개 이상의 hypertube를 경유하여 도달해야함을 알 수 있다.
Hypertube를 노드들의 이동을 위한 중간 노드로 생각하여 bus-topology를 구성하면 어떨까?
이 경우에, Hypertube자체를 노드로 취급하여 인접리스트를 구성한다면 그래프의 노드는 최악의 경우 200,000개가 될 것이고 연결관계는 최대 1,000개 이므로 메모리 초과 없이 문제를 해결할 수 있다.
주의해야할점은, hypertube 자체는 문제 해결을 위해 임의로 도입한 노드이므로 방문하는 역의 개수
에 포함 시키면 안된다는 것이다.
이 조건을 고려하기 위하여 Queue에는 현재 노드가 hypertube인지
파악할 수 있는 구분자가 필요하다.
현재 노드가 hypertube라면, 다음으로 방문할 노드가 station임이 보장되므로 이 경우에만 +1을 해준다음 최단 경로를 갱신한다.
소스코드
#define FASTIO cin.tie(0)->sync_with_stdio(false), cout.tie(0)
//////////////////////////////////////////////////////////////////
#include <bits/stdc++.h>
using namespace std;
int N, K, M;
int ans[100'001], tmp[100'001];
vector<int> adjHypertube[100'001];
vector<int> adjNodes[100'001];
int main(void){
FASTIO;
//////////////////////////////////////////////////////////////////
// mesh topology를 구성하는 것은 메모리 초과 (최악의 경우, 10^12에 근사)
cin >> N >> K >> M;
// adjHypertube[i] := i번 역에서 연결되어 있는 하이퍼튜브의 vector
// adjNodes[i] := i번 하이퍼튜브에서 갈 수 있는 정점들의 집합
for (int i = 1; i <= M; i++) {
for (int j = 0; j < K; j++) {
int node;
cin >> node;
adjNodes[i].push_back(node);
adjHypertube[node].push_back(i);
}
}
// {passedBy, 현재 노드, 현재 노드가 hyperTube인가?}
priority_queue<tuple<int, int, bool>, vector<tuple<int,int,bool>>, greater<>> PQ;
fill(ans, ans + 100'001, 1e9);
fill(tmp, tmp + 100'001, 1e9);
PQ.push({1, 1, false});
ans[1] = 1;
while (!PQ.empty()) {
auto[passedBy, cur, isHypertube] = PQ.top(); PQ.pop();
const vector<int>* adj;
if (isHypertube) {
adj = adjNodes;
} else {
adj = adjHypertube;
}
for (auto next: adj[cur]) {
bool nxtIsHypertube = !isHypertube;
if (!nxtIsHypertube && ans[next] <= passedBy + 1)
continue;
if (nxtIsHypertube && tmp[next] <= passedBy)
continue;
if (!nxtIsHypertube) {
ans[next] = passedBy + 1;
} else {
tmp[next] = passedBy;
}
PQ.push({passedBy + !nxtIsHypertube, next, nxtIsHypertube});
}
}
if (ans[N] == 1e9) ans[N] = -1;
cout << ans[N];
return 0;
}
'자료구조 + 알고리즘 > [BOJ]' 카테고리의 다른 글
[BOJ] 14658번 - 하늘에서 별똥별이 빗발친다 (1) | 2023.01.11 |
---|---|
[BOJ] 1911번 - 흙길 보수하기 (0) | 2023.01.10 |
[BOJ] 3109번 - 빵집 (0) | 2022.07.17 |
[BOJ] 1520번 - 내리막 길 (0) | 2022.07.13 |
[BOJ] 1781번 - 컵라면 (0) | 2022.06.30 |