난이도 : 골드 4
걸린 시간 : ㅎㅎ.. 오래 걸림
문제
풀이
- bfs를 이용하여 먹을 수 있는 고기 찾기 + 상어로부터의 거리 찾기
- 거리가 가장 가까운 먹을 수 있는 고기들 찾기
- 그 중 가장 왼쪽 위에 있는 고기 찾기
- 상어가 해당 물고기의 위치로 이동해서 먹고, 먹은 물고기 개수가 size와 같아지면 size 키우기
- 상어보다 작은 물고기가 없을 때까지 반복
코드
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
struct shark {
int r; int c;
int size = 2;
};
struct fish {
int r; int c;
int distance = 0;
fish(int rp, int cp, int dist) {
r = rp; c = cp; distance = dist;
}
};
int N;
int map[21][21];
int mapDist[21][21];
int direction[4][2] = { {0,-1}, {-1,0}, {1, 0}, {0,1} };
shark baby;
/* 먹을 수 있는 고기들을 따로 찾으면 실패함!
vector<pair<int, int>> findFish() {
// 먹을 수 있는 고기들의 위치 return
vector<pair<int, int>> res;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (map[i][j] != 0 && map[i][j] < baby.size) {
res.push_back(make_pair(i, j));
}
}
}
return res;
}
*/
vector<pair<int, int>> bfs() {
// 아기상어에서 모든 점까지의 최소 거리 찾기
fill(&mapDist[0][0], &mapDist[20][20], 1e9);
queue<pair<int, int>> que;
que.push(make_pair(baby.r, baby.c));
mapDist[baby.r][baby.c] = 0;
vector<pair<int, int>> fishes;
while (!que.empty()) {
pair<int, int> pos = que.front(); que.pop();
int row = pos.first; int col = pos.second;
for (int i = 0; i < 4; i++) {
int rtemp = row + direction[i][0];
int ctemp = col + direction[i][1];
if (rtemp < 0 || ctemp < 0 || rtemp >= N || ctemp >= N) // 맵 밖이면
continue;
if (mapDist[rtemp][ctemp] != 1e9) // 이미 들렀던 곳이면
continue;
if (map[rtemp][ctemp] == baby.size || map[rtemp][ctemp] == 0) { // size가 같거나 0이면 fishes에 넣지 x
mapDist[rtemp][ctemp] = (mapDist[row][col] + 1);
que.push(make_pair(rtemp, ctemp));
}
else if (map[rtemp][ctemp] < baby.size) {
fishes.push_back(make_pair(rtemp, ctemp));
mapDist[rtemp][ctemp] = (mapDist[row][col] + 1);
que.push(make_pair(rtemp, ctemp));
}
}
}
return fishes;
}
fish* findSmallest(vector<pair<int, int>>& fishes) {
// 가장 거리가 짧은 고기들 찾기
vector<pair<int, int>> mini;
int min = 1e9;
for (int i = 0; i < fishes.size(); i++) {
pair<int, int> fish = fishes[i];
if (min > mapDist[fish.first][fish.second]) { // min 갱신
min = mapDist[fish.first][fish.second];
mini.clear();
mini.push_back(make_pair(fish.first, fish.second));
}
else if (min == mapDist[fish.first][fish.second]) {
mini.push_back(make_pair(fish.first, fish.second));
}
}
// 왼쪽 위 고기 채택
fish* f = new fish(mini[0].first, mini[0].second, min);
for (int i = 1; i < mini.size(); i++) {
if (mini[i].first < f->r) {
// 더 위에 있으면
f->r = mini[i].first;
f->c = mini[i].second;
}
else if (mini[i].first == f->r && mini[i].second < f->c) {
// row는 같은데 왼쪽에 있으면
f->r = mini[i].first;
f->c = mini[i].second;
}
}
return f;
}
int main() {
cin >> N;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
cin >> map[i][j];
if (map[i][j] == 9) {
baby.r = i;// 상어 저장
baby.c = j;
map[i][j] = 0; // 맵에서 상어 지우기
}
}
}
int move = 0;
int eat = 0;
while (1) {
vector<pair<int, int>> fishes = bfs(); // 먹을 수 있는 고기 찾기 + 거리 표시
if (fishes.empty())
break;
fish* f = findSmallest(fishes); // 거리가 가장 가까우면서 왼쪽 위에 있는 고기 찾기
move += f->distance; // 이동 거리 더해주기
baby.r = f->r; baby.c = f->c; // 상어 이동
map[baby.r][baby.c] = 0; // 먹은 물고기는 map에서 0으로 만들기
eat++;
if (eat == baby.size) { // 크기만큼 물고기를 먹으면 크기가 1 커짐
baby.size++;
eat = 0;
}
}
cout << move << '\n';
}
주의할 점
bfs에서 바로 상어와의 크기를 비교해서 먹을 수 있는 고기들을 고르는 것과, 따로 map을 돌면서 미리 먹을 수 있는 고기들을 골라두는 것이 차이가 있나보다. 후자의 방법을 처음 택하였고 실패합니다가 떠서 전자의 방법으로 풀게 되었다.
후자의 방법도 반례를 모두 통과하는 게 함정..
결과
반응형
'Algorithm 문제 > BOJ' 카테고리의 다른 글
[c++] BOJ 1707 :: 이분 그래프 (0) | 2021.05.12 |
---|---|
[c++] BOJ 2206 :: 벽 부수고 이동하기 (0) | 2021.05.11 |
[c++] BOJ 1987 :: 알파벳 (0) | 2021.04.28 |
[c++] BOJ 10026 :: 적록색약 (0) | 2021.04.23 |
[c++] BOJ 14502 :: 연구소 (0) | 2021.04.22 |
Comment