www.acmicpc.net/problem/16236

 

16236번: 아기 상어

N×N 크기의 공간에 물고기 M마리와 아기 상어 1마리가 있다. 공간은 1×1 크기의 정사각형 칸으로 나누어져 있다. 한 칸에는 물고기가 최대 1마리 존재한다. 아기 상어와 물고기는 모두 크기를 가��

www.acmicpc.net


  • 먼저, 상어의 현재 위치에서 도착 할 수 있는 공간과 없는 공간(자신보다 크기가 큰 물고기)을 구별하고, 지나갈 수 있는 공간이라면 해당 위치까지의 거리를 구해놓는다.
  • BFS 를 이용해 모든 위치에 대해서 최단 거리를 구해놓고, 지나갈 수 없는 공간은 이상치를 저장해 놓는다.
  • 공간의 최대 넓이는 20 x 20 이므로 완전 탐색을 통해 위에서 구한 정보들로부터 가장 가까운 위치를 구한다.
  • 가장 가까운 위치에 있는 물고기를 먹는 처리를 해준다(상어 위치, 크기, 물고기 사라짐 처리 등)
  • 이 때 (0,0) 에서 (n,n) 의 방향으로 탐색할 경우 자연스럽게 "거리가 가까운 물고기가 많다면 가장 위에 있는 물고기, 그러한 물고기가 여러마리라면 가장 왼쪽에 있는 물고기를 먹는다" 라는 조건이 충족된다.
  • 만약 BFS 수행 후에 모든 공간에 대해서 이상치가 저장되어 있다면, 상어가 먹을 수 있는 물고기가 없기 때문에 종료해준다.

#include <iostream>
#include <algorithm>
#include <queue>
#define Point pair<int,int>

using namespace std;

int n;
int space[20][20];      // 실제 물고기들 정보
int visited[20][20];    // 각 위치까지의 거리에 대한 정보
Point shark_pos;        // 상어의 현재 위치
int shark_size = 2;     // 상어 현재 크기
int eatten = 0;         // 상어가 현재 사이즈에서 먹은 물고기 수
int timer = 0;
int dir[4] = {1, -1, 0, 0};

void distance()     // 물고기 현재 위치로부터 NxN 크기의 각 위치까지의 최단거리를 갱신하는 함수
{
    for(int i = 0 ; i < n ; i ++)
    {
        for(int j = 0 ; j < n ; j++)
        {
            visited[i][j] = 0;                              // 거리 정보 초기화
            if(space[i][j] > shark_size)                    // 지나갈 수 없는 칸에 대해서는 1000 으로 설정
                visited[i][j] = 1000;
        }
    }
    int dist = 0;
    queue<Point> q;                                     // 각 위치에 대해서 BFS
    q.push(shark_pos);                                      // 상어의 현재 위치부터 시작해서
    visited[shark_pos.first][shark_pos.second] = 1000;
    while(!q.empty())                                       // 상어가 도착할 수 있는 곳은 전부 탐색
    {
        int size = q.size();
        for(int i = 0 ; i < size ; i++)
        {
            Point temp = q.front();
            for(int j = 0, r, c ; j < 4 ; j++)
            {
                r = temp.first + dir[j];
                c = temp.second + dir[3 - j];
                if(0 <= r && r < n && 0 <= c && c < n)
                {
                    if(visited[r][c] == 0)
                    {
                        q.push(Point(r,c));
                        visited[r][c] = dist + 1;
                    }
                }
            }
            q.pop();
        }
        dist++;
    }
    for(int r = 0 ; r < n ; r++)
    {
        for(int c = 0 ; c < n ; c++)
        {
            if(visited[r][c] == 0) visited[r][c] = 1000;        // 만약 0 인 칸이 있으면, 도달할 수 없는 곳이라는 뜻이기 때문에 1000 으로 설정
        }
    }
}

int check()               // 물고기를 먹을지, 못 먹는지 체크해서 처리해주는 함수
{
    int cur_time = 1000, x, y;
    distance();                                                     // 현재 물고기 위치에서 각 위치까지의 최단거리 업데이트
    for(int r = 0 ; r < n ; r++)
    {
        for(int c = 0 ; c < n ; c++)
        {
            if(space[r][c] != 0 && space[r][c] < shark_size)            // 먹을 수 있는 물고기 중에
            {
                if(visited[r][c] < cur_time)                            // 가장 최단거리에 있는 물고기를 선택
                {                                                       // 왼위에서 오른아래로 탐색하기 때문에, 같은 거리의 물고기에 대한 조건 충족
                    x = r;
                    y = c;
                    cur_time = visited[r][c];
                }
            }
        }
    }

    if(cur_time == 1000) return 0;                                  // 먹을 수 있는 물고기가 없을 경우 cur_time 이 업데이트 되지 않아서 1000 이 유지된다.
                                                                // 물고기를 먹을 수 있다면
    timer += cur_time;                                              // 해당 위치까지 가는 시간만큼 더해주고
    shark_pos = Point(x,y);                                         // 상어의 위치를 옮겨주고
    space[x][y] = 0;                                                // 해당 위치의 물고기를 없애주고
    eatten++;                                                       // 먹은 횟수 1 증가시켜주는데
    if(eatten == shark_size)                                        // 만약 자신의 크기와 같은 수의 물고기를 먹은 상태라면
    {
        shark_size++;                                                   // 물고기 크기 증가시켜줌
        eatten = 0;
    }
    return 1;                                                       // 다시 반복
}

int main(void)
{
    cin.tie(0);
    ios_base::sync_with_stdio(0);

    cin >> n;
    for(int r = 0 ; r < n ; r++)
    {
        for(int c = 0 ; c < n ; c++)
        {
            cin >> space[r][c];
            if(space[r][c] == 9)
            {
                shark_pos = Point(r,c);                     // 상어의 위치를 업데이트 시켜주고
                space[r][c] = 0;                            // 상어는 움직일 예정이므로 빈칸인 0 으로 표시
            }
        }
    }

    while(check()) {}                                       // 더 이상 먹을 수 있는 물고기가 없을 때 까지 반복

    cout << timer << '\n';
}

'PS > BOJ' 카테고리의 다른 글

[백준] 16566.cpp : 카드 게임  (0) 2020.07.19
[백준] 15650.cpp : N과 M (2)  (0) 2020.07.17
[백준] 15686.cpp : 치킨 배달  (0) 2020.07.15
[백준] 14500.cpp : 테트로미노  (0) 2020.07.13
[백준] 17298.cpp : 오큰수  (0) 2020.07.12

+ Recent posts