※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※
이번에 볼 문제는 백준 25189번 문제인 시니컬한 개구리이다.
문제는 아래 링크를 확인하자.
https://www.acmicpc.net/problem/25189
25189번: 시니컬한 개구리
개구리는 $N \times M$ 격자 모양의 청정한 서식지에 살고 있다. 가장 왼쪽 위 칸의 좌표는 $(1,1)$이고 가장 오른쪽 아래 칸의 좌표는 $(N,M)$이다. 각 격자 칸에는 개구리밥이 있는데, 개구리는 자신이
www.acmicpc.net
개구리가 모든 점프가능한 에지를 하나하나 그린다면 약 20억개의 에지를 생성하게 되어 메모리초과 또는 시간초과를 받게 될 것이다. 이를 대신할 방법을 생각해내야 한다.
개구리밥을 무시한 점프를 시니컬점프라 부르자.
예제 3과 같이 개구리가 전혀 움직이지 않는 경우를 제외하면, 가능한 모든 경로는 (출발점 - 시니컬점프를 할 노드), (시니컬점프), (시니컬점프 도착 노드 - 도착점)의 형태로 나타낼 수 있다. 굳이 시니컬점프를 이용할 필요가 없더라도 경로상의 정상적인 점프 하나를 시니컬점프로 대신했다고 생각한다면 모든 경로는 위와 같이 표현이 가능하는 것을 알 수 있다.
시니컬점프는 하나의 행에 걸쳐서 사용하거나 하나의 열에 걸쳐서 사용한다. 따라서 (출발점 - 행)의 최소 점프횟수와 (행-도착점)의 소 점프횟수, 그리고 (출발점 - 열)의 최소 점프횟수와 (열 - 도착점)의 최소 점프횟수를 이용해 출발점에서 시니컬점프를 한번 이용해 도착점으로 이동하는 최소 점프횟수를 구해 문제를 해결할 수 있다.
아래는 제출한 소스코드이다.
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
int Sr, Sc, Er, Ec;
int R, C;
int S, E;
vector<int> G[1000000];
vector<int> invG[1000000];
int sdist[1000000];
int edist[1000000];
int dr[4] = { 1,-1,0,0 };
int dc[4] = { 0,0,1,-1 };
void bfs() {
memset(sdist, 0x3f, sizeof(sdist));
queue<int> que; que.push(S);
sdist[S] = 1;
while (!que.empty()) {
int cur = que.front(); que.pop();
for (auto& node : G[cur]) {
if (sdist[node] < 0x3f3f3f3f) continue;
sdist[node] = sdist[cur] + 1;
que.push(node);
}
}
}
void invbfs() {
memset(edist, 0x3f, sizeof(edist));
queue<int> que; que.push(E);
edist[E] = 1;
while (!que.empty()) {
int cur = que.front(); que.pop();
for (auto& node : invG[cur]) {
if (edist[node] < 0x3f3f3f3f) continue;
edist[node] = edist[cur] + 1;
que.push(node);
}
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> R >> C;
cin >> Sr >> Sc >> Er >> Ec;
Sr--, Sc--, Er--, Ec--;
S = Sr * C + Sc, E = Er * C + Ec;
if (S == E) {
cout << 0;
return 0;
}
for (int r = 0; r < R; r++) {
for (int c = 0; c < C; c++) {
int cur = r * C + c;
int x; cin >> x;
if (r - x > -1) {
int nxt = (r - x) * C + c;
G[cur].emplace_back(nxt);
invG[nxt].emplace_back(cur);
}
if (r + x < R) {
int nxt = (r + x) * C + c;
G[cur].emplace_back(nxt);
invG[nxt].emplace_back(cur);
}
if (c - x > -1) {
int nxt = r * C + (c - x);
G[cur].emplace_back(nxt);
invG[nxt].emplace_back(cur);
}
if (c + x < C) {
int nxt = r * C + (c + x);
G[cur].emplace_back(nxt);
invG[nxt].emplace_back(cur);
}
}
}
bfs();
invbfs();
int ans = 0x3f3f3f3f;
for (int r = 0; r < R; r++) {
int mn1 = 0x3f3f3f3f, mn2 = 0x3f3f3f3f;
for (int c = 0; c < C; c++) {
int idx = r * C + c;
mn1 = min(mn1, sdist[idx]), mn2 = min(mn2, edist[idx]);
}
ans = min(ans, mn1 + mn2 - 1);
}
for (int c = 0; c < C; c++) {
int mn1 = 0x3f3f3f3f, mn2 = 0x3f3f3f3f;
for (int r = 0; r < R; r++) {
int idx = r * C + c;
mn1 = min(mn1, sdist[idx]), mn2 = min(mn2, edist[idx]);
}
ans = min(ans, mn1 + mn2 - 1);
}
if (ans == 0x3f3f3f3f) cout << -1;
else cout << ans;
}
'BOJ' 카테고리의 다른 글
[BOJ 2381 // C++] 최대 거리 (0) | 2022.08.21 |
---|---|
[BOJ 14647 // C++] 준오는 조류혐오야!! (0) | 2022.08.21 |
[BOJ 25188 // C++] 1, 3, 모 나누기 (0) | 2022.08.19 |
[BOJ 25187 // C++] 고인물이 싫어요 (0) | 2022.08.18 |
[BOJ 17020 // C++] Train Tracking 2 (0) | 2022.08.17 |