Problem Solving

[Problem Solving] BOJ 19236 : 청소년 상어

__K.Jun__ 2024. 7. 2. 15:56

문제 링크 : https://www.acmicpc.net/problem/19236

#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include <algorithm>
using namespace std;

struct Fish
{
    int y;
    int x;
    int direction;
    bool isLive;
};
int graph[4][4];
Fish fishes[17];
int dy[] = {0, -1, -1, 0, 1, 1, 1, 0, -1};
int dx[] = {0, 0, -1, -1, -1, 0, 1, 1, 1};
int answer = 0;

void input();
void copy_state(int[][4], int[][4], Fish[], Fish[]);
bool isValid(int, int);
void swap_fish(int, int);
void move_fish();
void move_shark(int, int, int, int);
void make_state(int, int, int, int, int, bool);
void dfs(int, int, int, int);
void solve();
void output();

void input()
{
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            int number, direction;
            cin >> number >> direction;
            graph[i][j] = number;
            fishes[number] = {
                i,
                j,
                direction,
                true};
        }
    }
}

void copy_state(int copied_graph[][4], int graph[][4], Fish copied_fishes[], Fish fishes[])
{
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            copied_graph[i][j] = graph[i][j];
        }
    }

    for (int i = 1; i <= 16; i++)
    {
        copied_fishes[i] = fishes[i];
    }
}

bool isValid(int y, int x)
{
    return (0 <= y && y < 4 && 0 <= x && x < 4);
}

void swap_fish(int a, int b)
{
    Fish temp = fishes[a];
    fishes[a].y = fishes[b].y;
    fishes[a].x = fishes[b].x;
    fishes[b].y = temp.y;
    fishes[b].x = temp.x;
}

void move_fish()
{
    for (int i = 1; i <= 16; i++)
    {
        if (fishes[i].isLive != true)
            continue;
        int y = fishes[i].y;
        int x = fishes[i].x;
        int dir = fishes[i].direction;

        int ny = y + dy[dir];
        int nx = x + dx[dir];
        bool flag = false;

        if (isValid(ny, nx))
        {
            if (graph[ny][nx] == 0)
            {
                flag = true;
                fishes[i].y = ny;
                fishes[i].x = nx;
                graph[ny][nx] = i;
                graph[y][x] = 0;
            }
            else if (graph[ny][nx] != -1)
            {
                flag = true;
                swap_fish(i, graph[ny][nx]);
                swap(graph[y][x], graph[ny][nx]);
            }
        }

        if (flag == false)
        {
            int next_dir = dir;
            if (++next_dir == 9)
                next_dir = 1;
            int ny = y + dy[next_dir];
            int nx = x + dx[next_dir];

            while (next_dir != dir)
            {
                if (isValid(ny, nx))
                {
                    if (graph[ny][nx] == 0)
                    {
                        fishes[i].y = ny;
                        fishes[i].x = nx;
                        graph[ny][nx] = i;
                        graph[y][x] = 0;
                        fishes[i].direction = next_dir;
                        break;
                    }
                    else if (graph[ny][nx] != -1)
                    {
                        swap_fish(i, graph[ny][nx]);
                        swap(graph[y][x], graph[ny][nx]);
                        fishes[i].direction = next_dir;
                        break;
                    }
                }
                if (++next_dir == 9)
                    next_dir = 1;
                ny = y + dy[next_dir];
                nx = x + dx[next_dir];
            }
        }
    }
}

void make_state(int y, int x, int ny, int nx, int fishNum, bool flag)
{
    if (flag == true)
    {
        graph[y][x] = 0;
        graph[ny][nx] = -1;
        fishes[fishNum].isLive = false;
    }
    else if (flag == false)
    {
        graph[y][x] = -1;
        graph[ny][nx] = fishNum;
        fishes[fishNum].isLive = true;
    }
}

void move_shark(int y, int x, int dir, int sum)
{
    for (int i = 1; i <= 3; i++)
    {
        int ny = y + i * dy[dir];
        int nx = x + i * dx[dir];
        if (isValid(ny, nx))
        {
            if (graph[ny][nx] == 0)
                continue;
            int cur_fishNum = graph[ny][nx];
            int cur_dir = fishes[cur_fishNum].direction;
            make_state(y, x, ny, nx, cur_fishNum, true);
            dfs(ny, nx, cur_dir, sum + cur_fishNum);
            make_state(y, x, ny, nx, cur_fishNum, false);
        }
        else
            break;
    }
}

void dfs(int y, int x, int dir, int sum)
{
    answer = max(answer, sum);
    int copied_graph[4][4];
    Fish copied_fishes[17];

    copy_state(copied_graph, graph, copied_fishes, fishes);
    move_fish();
    move_shark(y, x, dir, sum);
    copy_state(graph, copied_graph, fishes, copied_fishes);
}

void solve()
{
    int cur_fishNum = graph[0][0];
    int cur_dir = fishes[cur_fishNum].direction;
    fishes[cur_fishNum].isLive = false;
    graph[0][0] = -1;
    dfs(0, 0, cur_dir, cur_fishNum);
}

void output()
{
    cout << answer << endl;
}

int main(void)
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    input();
    solve();
    output();
    return 0;
}

graph의 각 원소는 0일 때 비어있는 곳, -1 일때 상어가 있는 곳, 1~16 일때는 물고가가 있는 곳임을 의미한다.

fishes는 1번부터 16번 물고기의 상태를 나타내는 Fish 구조체 타입의 배열이다.

 

1. 상어는 (0, 0) 위치에 있는 물고기부터 잡아먹고, 그 물고기와 같은 방향을 향한다. 그리고 잡아 먹힌 물고기의 isLive는 false가 되고, graph[0][0]는 -1이 된다.

 

2. (0, 0)을 기점으로 하여 가능한 모든 조합을 dfs하여 answer의 최댓값을 찾는다.

2-1. 물고기를 이동시키기 전에 fishes와 graph를 복제하여 놓는다.

2-2. 물고기를 이동시킨다. (물고기가 이동하는 방식은 빈 자리로 이동하는 방식, 다른 물고기와 자리를 바꾸는 방식으로 두가지이다.)

2-3. 상어를 이동시키는데, 모든 조합을 탐색해야 하기 때문에, 물고기를 잡아 먹고 dfs를 재귀 호출 한 후, 재귀 호출이 끝나면 다시 물고기를 잡아 먹기 전 상태로 돌아온다.

2-4. 복제해 놓은 fishes와 graph를 복구한다.

 

3. 완전 탐색 후 얻은 answer의 최댓값을 출력한다.

728x90