[문제]
https://www.acmicpc.net/problem/16236
16236번: 아기 상어
N×N 크기의 공간에 물고기 M마리와 아기 상어 1마리가 있다. 공간은 1×1 크기의 정사각형 칸으로 나누어져 있다. 한 칸에는 물고기가 최대 1마리 존재한다. 아기 상어와 물고기는 모두 크기를 가
www.acmicpc.net
[풀이]
일단 조건이 많아서 복잡해 보이는데,,,흐름을 정리하자면 다음과 같다.
1. 아기 상어가 처음 위치한 곳에서 BFS를 돌린다. 아기 상어가 먹을 수 있는 물고기가 더이상 없을 때까지 반복하며 먹을 수 있는 물고기의 거리, 위치를 eat_fish vector에 저장한다.
2. BFS가 끝나면 아기 상어가 먹으러 갈 물고기를 찾는다.
1) 가장 가까운 곳에 위치한 물고기
2) 가장 위에 있는 물고기 (=y좌표가 작은 순서)
3) 가장 왼쪽에 있는 물고기 (=x좌표가 작은 순서)
조건은 다음과 같다. 애초에 eat_fish vector를 { 거리, { y좌표, x좌표} } 로 저장했으므로 sort를 하면 조건에 맞게 정렬된다.
3. 아기 상어가 잡아 먹은 물고기의 위치를 통해 몇 초 이동했는지 정답을 갱신하고, 그 위치에서 다시 BFS를 시작한다. 아기 상어가 해당 위치에 있는 물고기를 잡아 먹었으므로 map[r][c] 는 0으로 바꿔준다.
4. 아기 상어가 잡아 먹은 물고기의 count를 증가시켜준다. 만약 count가 아기 상어 크기와 같아지면, 아기 상어 크기를 증가시키고 count는 다시 0으로 초기화한다.
추가로 BFS 돌릴 때마다 eat_fish vector랑 check 배열 초기화 해주기!
[코드]
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace::std;
int n;
int map[21][21];
int check[21][21];
int dx[] = {0, 0, -1, 1};
int dy[] = {1, -1, 0, 0};
vector<pair<int, pair<int, int>>> eat_fish;
int r, c;
int bs = 2;
void bfs(int y, int x, int bs){ //bs 아기 상어 크기
memset(check, -1, sizeof(check));
eat_fish.clear();
queue<pair<int,int>> q;
q.push({y,x});
check[y][x] = 0;
while(!q.empty()){
y = q.front().first;
x = q.front().second;
q.pop();
for(int i=0; i<4; i++){
int nr = y + dy[i];
int nc = x + dx[i];
if(nr < 0 || nr >= n || nc < 0 || nc >= n || check[nr][nc]!=-1 || map[nr][nc] > bs) continue;
if(map[nr][nc]==0 || map[nr][nc]==bs){ //지나갈 수 있음
check[nr][nc] = check[y][x] + 1; //아기 상어로부터 얼마나 멀리 떨어졌는지 기록
q.push({nr, nc});
}
if(map[nr][nc]<bs && map[nr][nc]>=1){ //잡아 먹고, 지나갈 수 있음
check[nr][nc] = check[y][x] + 1;
eat_fish.push_back( {check[nr][nc],{nr, nc}});
q.push({nr, nc});
}
}
}
}
int main() {
int count = 0, answer=0;
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){
map[i][j] = 0; //크기를 9로 인식해서 아기상어가 해당 위치를 못지나갈 수 있으므로 0으로 초기화
r = i;
c = j;
}
}
}
while(true){
bfs(r, c, bs);
if(eat_fish.empty())
break;
//1. 가장 가까운 2. 가장 위에 있는(y좌표가 작은) 3. 가장 왼쪽에 있는(x좌표가 작은)
sort(eat_fish.begin(), eat_fish.end());
count++; // 아기 상어가 먹은 물고기 수
answer += eat_fish[0].first; //아기 상어가 물고기를 먹으러 몇 초 이동했는지
r = eat_fish[0].second.first;
c = eat_fish[0].second.second; //아기 상어 위치 갱신
map[r][c] = 0; //아기상어가 잡아먹어서 0이 됨
if(bs == count){
bs++; //아기 상어 크기 증가
count = 0;
}
}
cout << answer;
}
'알고리즘 공부 및 문제 풀이 > 백준(BOJ)' 카테고리의 다른 글
[boj] 백준 2357 최솟값과 최댓값 (c++) - 세그먼트 트리 (0) | 2022.05.19 |
---|---|
[boj] 백준 2098 외판원 순회 (c++) - TSP(비트마스킹, dp, dfs) (0) | 2022.05.18 |
[boj] 백준 2252 줄 세우기 - 위상정렬 (0) | 2022.03.30 |
[boj] 백준 2493 탑 - stack (0) | 2022.03.25 |
[boj] 백준 2565 전깃줄 - dp, 증가하는 수열 (0) | 2022.03.18 |