[BOJ][C#] 20056 마법사 상어와 파이어볼

LimJaeJun·2024년 1월 18일
0

PS/BOJ

목록 보기
101/108

📕 문제

📌 링크

📗 접근 방식

포인트 클래스와 파이어볼 클래스를 정의

  • 파이어볼 클래스
    • r, c, m, s,d를 저장함 (사실 r, c 데이터는 기록 안해도 됨)
  • 포인트 클래스
    • 파이어볼을 리스트로 들고 있음 (파이어볼이 Combine된 개수를 알아야하기 때문에 리스트로 저장함)

K번 반복

  • 파이어볼 이동
  • 파이어볼 확산 및 머지

파이어볼 이동

  • 양 끝에서 보드 밖으로 이동 시, 반대편으로 나올 수 있다는 것을 유의

파이어볼 확산 및 머지

  • 2개이상의 파이어볼을 가지고 있는 포인트에서만 진행

위에 것들을 이용하여 문제와 똑같이 구현하여 풀었다.
단순히 구현, 시뮬레이션이였던 것 같았다.

📘 코드

namespace BOJ
{
    static class Input<T>  
    {
        public static T[] GetInputArray() => Array.ConvertAll(Console.ReadLine().Split(), ConvertStringToType);
        private static T ConvertStringToType(string input) => (T)Convert.ChangeType(input, typeof(T));
    }
    
    class FireBall
    {
        public int row, col, mass, speed, direction;

        public FireBall(int r, int c, int m, int s, int d)
        {
            row = r;
            col = c;
            mass = m;
            speed = s;
            direction = d;
        }
    }
    
    class Point
    {
        public List<FireBall> fireballs;
        
        public Point()
        {
            fireballs = new List<FireBall>();
        }

        public void AddFireBall(FireBall fireBall)
        {
            fireballs.Add(fireBall);
        }
    }

    class No_20056
    {
        static int N, M, K;
        static Point[,] board;
        static int[] dx = { -1, -1, 0, 1, 1, 1, 0, -1 };
        static int[] dy = { 0, 1, 1, 1, 0, -1, -1, -1 };

        static void Main()
        {
            var inputs = Input<int>.GetInputArray();

            N = inputs[0];
            M = inputs[1];
            K = inputs[2];

            board = new Point[N + 1, N + 1];

            for (int i = 0; i < M; i++)
            {
                inputs = Input<int>.GetInputArray();
                int r = inputs[0];
                int c = inputs[1];
                int m = inputs[2];
                int s = inputs[3];
                int d = inputs[4];

                FireBall fireBall = new FireBall(r, c, m, s, d);
                if (board[r, c] == null)
                    board[r, c] = new Point();
                board[r, c].AddFireBall(fireBall);
            }

            // K번 이동
            for (int i = 0; i < K; i++)
            {
                MoveFireBalls();
                MergeFireBalls();
            }

            // 남아있는 파이어볼 질량의 합 출력
            int result = GetRemainingMass();
            Console.WriteLine(result);
        }    
        static void MoveFireBalls()
        {
            // 이동한 위치에 새로 파이어볼 추가
            Point[,] newBoard = new Point[N + 1, N + 1];

            for (int r = 1; r <= N; r++)
            {
                for (int c = 1; c <= N; c++)
                {
                    if (board[r, c] != null)
                    {
                        foreach (FireBall fireBall in board[r, c].fireballs)
                        {
                            int nr = (r + (fireBall.speed % N) * dx[fireBall.direction] + N - 1) % N + 1;
                            int nc = (c + (fireBall.speed % N) * dy[fireBall.direction] + N - 1) % N + 1;

                            if (newBoard[nr, nc] == null)
                                newBoard[nr, nc] = new Point();

                            newBoard[nr, nc].AddFireBall(fireBall);
                        }
                    }
                }
            }

            board = newBoard;
        }

        static void MergeFireBalls()
        {
            // 2개 이상의 파이어볼이 있는 칸에서 합치기
            for (int r = 1; r <= N; r++)
            {
                for (int c = 1; c <= N; c++)
                {
                    if (board[r, c] == null || board[r, c].fireballs.Count < 2) continue;
                    
                    List<FireBall> mergedFireBalls = new List<FireBall>();
                    int totalMass = 0, totalSpeed = 0, oddCount = 0, evenCount = 0;

                    foreach (FireBall fireBall in board[r, c].fireballs)
                    {
                        totalMass += fireBall.mass;
                        totalSpeed += fireBall.speed;

                        if (fireBall.direction % 2 == 0)
                            evenCount++;
                        else
                            oddCount++;
                    }

                    int newMass = totalMass / 5;
                    int newSpeed = totalSpeed / board[r, c].fireballs.Count;

                    if (newMass > 0)
                    {
                        if (oddCount == 0 || evenCount == 0)
                        {
                            for (int d = 0; d < 4; d++)
                            {
                                mergedFireBalls.Add(new FireBall(r, c, newMass, newSpeed, d * 2));
                            }
                        }
                        else
                        {
                            for (int d = 1; d < 8; d += 2)
                            {
                                mergedFireBalls.Add(new FireBall(r, c, newMass, newSpeed, d));
                            }
                        }
                    }

                    board[r, c].fireballs = mergedFireBalls;
                }
            }
        }

        static int GetRemainingMass()
        {
            int result = 0;
            for (int r = 1; r <= N; r++)
            {
                for (int c = 1; c <= N; c++)
                {
                    if (board[r, c] != null)
                    {
                        result += board[r, c].fireballs.Sum(fireBall => fireBall.mass);
                    }
                }
            }
            return result;
        }
    }
}

📙 오답노트

📒 알고리즘 분류

  • 구현
  • 시뮬레이션
profile
Dreams Come True

0개의 댓글

관련 채용 정보