2020. 8. 9. 04:32ㆍAlgorithm Problem Solving
Gold II https://www.acmicpc.net/problem/17143
17143번: 낚시왕
낚시왕이 상어 낚시를 하는 곳은 크기가 R×C인 격자판으로 나타낼 수 있다. 격자판의 각 칸은 (r, c)로 나타낼 수 있다. r은 행, c는 열이고, (R, C)는 아래 그림에서 가장 오른쪽 아래에 있는 칸이다.
www.acmicpc.net
Problem
- R×C 크기의 격자판에서 낚시왕이 상어 낚시를 한다. 칸에는 상어가 최대 한 마리 들어있을 수 있고, 상어는 크기와 속도를 가지고 있다. 낚시왕은 처음 1번 열의 한 칸 왼쪽에 있다.
- 1초 동안 아래에 적힌 일이 순서대로 일어난다.
1) 낚시왕이 오른쪽으로 한 칸 이동한다.
2) 낚시왕이 있는 열에 있는 상어 중에서 땅과 제일 가까운 상어를 잡는다. 상어를 잡으면 격자판에서 잡은 상어가 사라진다.
3) 상어가 방향과 속도에 따라 이동한다. 이 때, 상어가 이동하려고 하는 칸이 격자판의 경계를 넘는 경우에는 방향을 반대로 바꿔서 속력을 유지한 채로 이동한다. 한 칸에 상어가 여러 마리 존재하는 경우 가장 큰 상어만 남는다. - 낚시왕이 잡은 상어 크기의 합을 구한다.
Solution
문제에 그림 많고 시뮬레이션하는, 제가 좋아하는 유형의 문제라서 되게 재미있게 풀었습니다.
먼저, 각 상어의 위치, 속력, 방향, 크기를 가지고 있는 상어 구조체를 만들었습니다. 낚시터의 각 칸마다 상어를 넣습니다. (저는 pop, push 연산을 편하게 하려고 벡터를 사용했지만, 굳이 벡터를 사용하지 않아도 됩니다.. ㅎㅎ) 그 뒤는 문제에서 시키는 대로 구현해주면 되는데, 처음에는 상어의 위치를 바꿀 때 상어의 속력만큼 while문을 돌리면서 한 칸씩 이동하는 식으로 구현해서 시간 초과를 받았습니다. (낚시왕은 100번 이동 가능하고, 상어의 개수는 총 10000마리까지 가능한데, 속력인 s가 1000까지 가능하다보니 당연히 시간 초과..😂)
생각해보니 위, 아래 방향으로 움직이는 상어의 경우 속력이 (R - 1) * 2배일 때, 좌우로 움직이는 상어의 경우 속력이 (C - 1) * 2배 일 때 같은 자리의 똑같은 방향으로 돌아오게 됩니다. 따라서 처음 상어의 속력을 저장할 때 최소의 경우만 생각할 수 있도록 방향에 따라 (R - 1) * 2 또는 (C - 1) * 2로 나눈 나머지를 속력으로 저장해서 시간 초과 문제를 해결했습니다. 이 부분이 해당 문제를 푸는 키포인트겠네요.
정리하자면 아래와 같습니다.
- 상어가 원래 자리로 돌아오는 경우를 제외하고 최소의 이동거리만 저장한다.
- 낚시왕을 이동시키고 해당 거리에서 제일 가까운 거리의 상어를 잡은 뒤(pop_back) 답에 더해준다.
- 벡터에 상어가 존재할 경우 pop해주고, 상어의 속력만큼 while문을 돌리면서 다음 위치를 찾는다.
- 다음 위치에 상어가 있을 경우, 크기를 비교해서 현재 상어가 크기가 더 큰 경우 상어를 바꿔주고, 현재 상어가 더 작으면 현 상태를 유지한다. 상어가 없는 경우 현재 상어를 바로 넣는다.
- 2~4 과정을 낚시왕이 열의 가장 끝 부분에 도착할 때까지 반복한다.
Code
// https://www.acmicpc.net/problem/17143 | |
#include <iostream> | |
#include <vector> | |
using namespace std; | |
const int dir[5][2] = { {0, 0}, {-1, 0}, {1, 0}, {0, 1}, {0, -1} }; | |
struct Shark { | |
int r, c, s, d, z; | |
// 위치, 속력, 방향, 크기 | |
}; | |
int R, C, M; // 격자판 크기, 상어의 개수 | |
int Answer; | |
vector<Shark> Sharks[102][102]; // [i][j] 위치에서의 상어 | |
bool in_range(int r, int c) { | |
return 0 < r && r <= R && 0 < c && c <= C; | |
} | |
int change_dir(int d) { | |
if (d == 1) return 2; | |
if (d == 2) return 1; | |
if (d == 3) return 4; | |
if (d == 4) return 3; | |
} | |
int main() { | |
cin >> R >> C >> M; | |
for (int i = 0; i < M; i++) { | |
int r, c, s, d, z; | |
cin >> r >> c >> s >> d >> z; | |
if (d == 1 || d == 2) s %= ((R - 1) * 2); // 상어가 원래 자리로 돌아오는 경우, | |
if (d == 3 || d == 4) s %= ((C - 1) * 2); // 해당 부분은 빼고 최소 속도만 고려한다. | |
Sharks[r][c].push_back({ r, c, s, d, z }); | |
} | |
int K = 0; | |
while (++K <= C) { | |
// 1. 해당 열에서 제일 가까운 상어 잡기 | |
for (int i = 1; i <= R; i++) { | |
if (!Sharks[i][K].empty()) { | |
Answer += Sharks[i][K][0].z; | |
Sharks[i][K].pop_back(); | |
break; | |
} | |
} | |
vector<Shark> newSharks[102][102]; // 중복 이동을 방지하기 위해 새로운 상어를 저장 | |
// 2. 상어 이동 | |
for (int i = 1; i <= R; i++) { | |
for (int j = 1; j <= C; j++) { | |
if (Sharks[i][j].empty()) continue; | |
Shark currShark = Sharks[i][j][0]; | |
Sharks[i][j].pop_back(); | |
int& cr = currShark.r; | |
int& cc = currShark.c; | |
int cs = currShark.s; | |
int& cd = currShark.d; | |
while (cs--) { | |
int nr = cr + dir[cd][0]; | |
int nc = cc + dir[cd][1]; | |
if (!in_range(nr, nc)) { | |
cd = change_dir(cd); | |
} | |
cr += dir[cd][0]; | |
cc += dir[cd][1]; | |
} | |
// 3. 상어가 있을 경우 큰거 하나만 남기기 | |
if (!newSharks[cr][cc].empty()) { | |
if (newSharks[cr][cc][0].z < currShark.z) { | |
newSharks[cr][cc].pop_back(); | |
newSharks[cr][cc].push_back(currShark); | |
} | |
} | |
// 상어가 없으면 바로 push | |
else newSharks[cr][cc].push_back(currShark); | |
} | |
} | |
// 새로운 상어를 기존 상어 배열에 복사 | |
for (int i = 1; i <= R; i++) { | |
for (int j = 1; j <= C; j++) { | |
Sharks[i][j] = newSharks[i][j]; | |
} | |
} | |
} | |
cout << Answer << endl; | |
return 0; | |
} |
'Algorithm Problem Solving' 카테고리의 다른 글
[APS] 백준 15998. 카카오머니 C++ 풀이 (최대공약수, GCD, 유클리드 알고리즘) (0) | 2020.08.26 |
---|---|
[APS] 프로그래머스 60058. 괄호 변환 C++ 풀이 (substr) (0) | 2020.08.25 |
[APS] SWEA 9780. 외계인 침공 C++ 풀이 (DP) (0) | 2020.04.25 |
[APS] 백준 3649. 로봇 프로젝트 C++ 풀이 (0) | 2020.04.06 |
[APS] 백준 9998. 블록 쌓기 C++ 풀이 (이분 탐색) (1) | 2020.04.04 |