난이도 ★★★★☆
문제출처
16236번: 아기 상어
N×N 크기의 공간에 물고기 M마리와 아기 상어 1마리가 있다. 공간은 1×1 크기의 정사각형 칸으로 나누어져 있다. 한 칸에는 물고기가 최대 1마리 존재한다. 아기 상어와 물고기는 모두 크기를 가지고 있고, 이 크기는 자연수이다. 가장 처음에 아기 상어의 크기는 2이고, 아기 상어는 1초에 상하좌우로 인접한 한 칸씩 이동한다. 아기 상어는 자신의 크기보다 큰 물고기가 있는 칸은 지나갈 수 없고, 나머지 칸은 모두 지나갈 수 있다. 아기 상어는 자신의 크
www.acmicpc.net
포인트
1. bfs(최단거리 탐색)
상어는 먹을 수 있는 물고기 중, 가장 '가까이에 있는' 물고기를 먹어야 하므로, 구현을 할 때에는 상어가 먹을 수 있는 모든 물고기에 대하여 상어까지의 거리를 bfs로 탐색해서 구한다.
1-1. bfs에서 사용할 queue는 bfs 함수 내에서 선언한다. 그렇게 하지 않을 시에는, bfs를 호출할 때마다 이전 호출 때 사용했던 큐를 비워주어야 한다는 단점이 있다.
1-2. 단순히 탐색을 하는 것이 아니라, 최단 거리, 즉 depth를 구하기 위해서는 queue 사이즈가 다 될 때마다 depth를 하나씩 증가시켜주는 것을 구현해야 한다.(dist++)
2. 먹을 수 있는 물고기가 없는 경우
2-1. 물고기가 아예 존재하지 않는 경우 : 애초에 fishes 벡터에 아무 물고기도 담기지 않기 때문에,
if(fishes.size==0) break;
로 종료 가능하다.
2-2. 물고기는 존재하지만, 크기가 모두 상어보다 커서 먹지 못하는 경우: 상어보다 사이즈가 작은 물고기에 대해서만 거리를 구해주므로, 거리값이 갱신되지 않은 경우, 즉 minDist=INF상태로 그대로 남아있는 경우에 break가 가능하다.
2-3. 물고기도 존재하고, 크기가 상어보다 작은 물고기도 있지만, 경로가 큰 물고기에 의해 모두 막혀있는 경우 : 이 경우, 물고기들이 저장된 벡터도 존재(2-1의 반대 상황)하고, minDist값도 갱신(2-2의 반대 상황)된다. 그렇기 때문에 새로운 변수 flag를 사용한다. bfs함수 내에서, 상어를 만날 수 있는 경우에만 flag를 true값으로 반환하고, true값이 된 경우에만 minDist를 갱신하도록 한다. 따라서 flag 처리를 통해 2-2에서와 같이 거리값 갱신 여부로 break처리를 할 수 있게 된다.
3. 상어 이동
처리해야 할 것들이 은근 많다.
3-1. 시간을 타겟 물고기와의 거리만큼 늘려준다. (ans+=target.dist)
3-2. 원래 상어가 있던 자리를 비워준다. (map[babyShark.r][babyShark.c]=0)
3-3. 상어 위치를 저장해준다. (babyShark.r=target.r, babyShark.c=target.c)
3-4. 타겟이 있던 곳을 상어로 바꿔준다. (map[target.r][target.c]=9)
3-5. 상어 먹이 횟수를 하나 카운트해준다. cnt++
3-6. 상어가 먹은 물고기가 상어 사이즈와 같은지 체크해준다 if(cnt==babyShark.size)
3-6-1. 같을 경우, cnt=0으로 초기화해주고, babyShark.size는 +=1처리한다.
3-7. 상어 이동 후 먹이의 개수가 달라졌으므로 기존 fishes벡터를 초기화하고 다시 저장한다.
정답소스
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int INF = 987654321;
bool flag = false;
int N;
int map[25][25];
int visit[25][25];
int dx[4] = { 0,0,1,-1 };
int dy[4] = { 1,-1,0,0 };
int ans = 0;
int dist = 0;
int minDist = INF;
struct fish {
int r;
int c;
int size;
int dist;
};
struct shark {
int r;
int c;
int size;
};
vector<fish> fishes;
shark babyShark;
bool range(int r, int c) {
if (r >= 0 && r < N&&c >= 0 && c < N)return true;
return false;
}
void initialize() {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
visit[i][j] = 0;
}
}
}
void bfs(int r, int c) {
flag = false;
visit[r][c] = 1;
queue<pair<int, int>> q;
q.push(make_pair(r, c));
while (!q.empty()) {
int sz = q.size();
dist++;
while (sz--) {
r = q.front().first;
c = q.front().second;
q.pop();
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
int nr = r + dy[i];
int nc = c + dx[i];
if (range(nr, nc) && map[nr][nc] == 9) {
flag = true;
return;
}
if (range(nr, nc) && !visit[nr][nc] && map[nr][nc] <= babyShark.size) {
visit[nr][nc] = 1;
q.push(make_pair(nr, nc));
}
}
}
}
}
return;
}
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] >= 1 && map[i][j] <= 6) {
fishes.push_back({ i,j,map[i][j],0 });
}
else if (map[i][j] == 9) {
babyShark = { i,j,2 };
}
}
}
int cnt = 0;
while (true) {
if (fishes.size() == 0)break;
fish target = { 0,0,0,minDist };
for (int i = 0; i < fishes.size(); i++) {
if (fishes[i].size < babyShark.size) {
dist = 0;
initialize();
bfs(fishes[i].r, fishes[i].c);
if (flag)fishes[i].dist = dist;
else fishes[i].dist = INF;
if (target.dist > fishes[i].dist) {
target = fishes[i];
minDist = target.dist;
}
else if (target.dist == fishes[i].dist) {
if (target.r > fishes[i].r)target = fishes[i];
else if (target.r == fishes[i].r) {
if (target.c > fishes[i].c)target = fishes[i];
}
minDist = target.dist;
}
}
}
if (minDist == INF)break;
ans += target.dist;
map[babyShark.r][babyShark.c] = 0;
babyShark.r = target.r;
babyShark.c = target.c;
map[babyShark.r][babyShark.c] = 9;
cnt++;
if (cnt == babyShark.size) {
babyShark.size += 1;
cnt = 0;
}
fishes.clear();
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (map[i][j] >= 1 && map[i][j] <= 6) {
fishes.push_back({ i,j,map[i][j],0 });
}
}
}
if (fishes.size() == 0)break;
minDist = INF;
}
cout << ans << '\n';
return 0;
}
'알고리즘 > 삼성' 카테고리의 다른 글
삼성 코딩테스트 기출_(백준)인구이동 (0) | 2019.10.17 |
---|---|
삼성 코딩테스트 기출_(백준)2048(Easy) (1) | 2019.10.15 |
삼성 코딩테스트 기출_(백준)테트로미노 (0) | 2019.10.04 |
삼성 코딩테스트 기출_(백준)로봇 청소기 (1) | 2019.10.02 |
삼성 코딩테스트 기출_(백준)톱니바퀴 (0) | 2019.10.01 |
댓글