알고리즘
BOJ: 아기 상어(16236) [C++]
avocado8
2024. 7. 7. 18:11
https://www.acmicpc.net/problem/16236
그래프 탐색. 조건이 길게 적혀있는데
- 더 이상 먹을 수 있는 물고기가 공간에 없다면 아기 상어는 엄마 상어에게 도움을 요청한다.
- 먹을 수 있는 물고기가 1마리라면, 그 물고기를 먹으러 간다.
- 먹을 수 있는 물고기가 1마리보다 많다면, 거리가 가장 가까운 물고기를 먹으러 간다.
- 거리는 아기 상어가 있는 칸에서 물고기가 있는 칸으로 이동할 때, 지나야하는 칸의 개수의 최솟값이다.
- 거리가 가까운 물고기가 많다면, 가장 위에 있는 물고기, 그러한 물고기가 여러마리라면, 가장 왼쪽에 있는 물고기를 먹는다.
탐색 시 우선순위는 거리가 가까움 / 가장 위에 있음(y좌표가 최소) / 가장 왼쪽에 있음(x좌표가 최소) 에 따라 정해진다.
우선순위 큐를 사용한 BFS로 먹을 수 있는 물고기를 탐색해준다.
상어의 크기, 위치, 이동한 거리, 그에 따른 시간을 잘 다뤄주어야 할 듯하다
1. bfs를 통해 먹을 물고기 찾음
2. 물고기를 먹으면 그 칸으로 이동, 자신의 크기와 같은 수의 물고기를 먹을 때마다 크기 증가, 먹힌 칸은 빈 칸으로
3. 더 먹을 물고기가 없으면 종료 (크기가 딸릴 수도, 다 먹어서 없을 수도...->먹은 물고기 수도 저장 필요)
/******************************************************************************
Online C++ Compiler.
Code, Compile, Run and Debug C++ program online.
Write your code in this editor and press "Run" button to compile and execute it.
*******************************************************************************/
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
typedef pair<int, int> ci;
int dx[4] = { 0, 0, -1, 1};
int dy[4] = { -1, 1, 0, 0}; //상하좌우
pair<int, ci> babyShark(int n, int size, ci loc, vector<vector<int>>&board){
priority_queue<pair<int, ci>, vector<pair<int,ci>>, greater<pair<int,ci>>> pq; //먹을 수 있는 후보 물고기 저장. first(int): 거리, second(ci): 좌표(y,x)
queue<ci> q; //좌표(y,x) 저장할 큐
vector<vector<int>> dist(n, vector<int>(n,0)); //이동거리
dist[loc.first][loc.second] = 1; //현재 상어 위치
q.push(loc);
while(!q.empty()){
ci curr = q.front(); //현재 상어위치 가져옴
q.pop();
for(int i=0;i<4;i++){ //상하좌우 각각에 대해 bfs
ci next = { curr.first + dy[i], curr.second + dx[i] }; //상어의 다음 위치 탐색
if(next.first >=0 && next.first<n && next.second>=0 && next.second<n){ //보드 범위 벗어나지 않게
if(dist[next.first][next.second]) continue; //이미 방문
if(board[next.first][next.second] > size) continue; //물고기가 상어보다 크면 못 지나감(같으면 지나갈 수는 있음)
//먹을 수 있는 경우
if(board[next.first][next.second] && board[next.first][next.second] < size){
pq.push({dist[curr.first][curr.second], next}); //후보 물고기 우선순위큐에 푸시
continue;
}
dist[next.first][next.second] = dist[curr.first][curr.second] + 1; //한칸 이동했으므로 1 더함
q.push(next); //상어의 다음 위치 저장
}
}
}
if(pq.empty()){ //후보가 될 수 있는 물고기가 없다면
return { -1, {-1,-1} }; //-1 리턴
}
//물고기 먹기(우선순위큐 제일 앞에 있는 걸로)
board[pq.top().second.first][pq.top().second.second] = 0; //물고기를 먹으면 빈칸이 됨
return pq.top(); //dist(==혼자 돌아댕긴 시간)와 그때 위치를 리턴
}
int solution(int n, ci loc, vector<vector<int>>&board){
int size = 2; //초기 상어크기는 2
int cnt = 0; //먹은 물고기 수
int t = 0; //걸린 시간
board[loc.first][loc.second] = 0; //상어 초기위치 빈칸으로 설정
while(true){
pair<int, ci> baby_shark = babyShark(n, size, loc, board);
if(baby_shark.first == -1) break; //먹을 물고기가 없으면 종료
cnt++; //그렇지 않으면 물고기 하나 먹음
t += baby_shark.first; //시간 증가
if(cnt == size) { //자신의 크기와 같은 수의 물고기를 먹었으면
size++; //상어크기 증가
cnt = 0; //먹은 물고기 수 초기화
}
loc = baby_shark.second; //변경된 상어 위치
}
return t;
}
int main()
{
int n, size;
cin >> n;
vector<vector<int>> board;
board.assign(n, vector<int>(n, 0));
ci shark_loc;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin >> board[i][j];
if(board[i][j]==9) shark_loc = {i, j};
}
}
int answer = solution(n, shark_loc, board);
cout << answer << '\n';
return 0;
}
주석을 열심히 달며 이해해보려 몸부림치기
어렵다어려워
어케푸냐이런걸
즐건식사