코딩테스트/Java

[JAVA] 백준 마법사 상어와 토네이도

SK_MOUSE 2021. 10. 21. 15:27
반응형

간단한 구현문제이다.

https://www.acmicpc.net/problem/20057

코드에 대한 욕심때문에 방향에 대한 dx,dy만 정해놓고 나머지는 회전하면서 전개해 나가려고 코드를 작성하였는데, 방향에 따른 왼쪽 오른쪽 구분이 일관되게 진행할 수 없어서 중간에 모래가 사라지게 되었다.

잘못된 코드는 아래 첨부하겠다.

더보기
import jdk.swing.interop.SwingInterOpUtils;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
    static int N;
    static int[][] grid;
    static int[] dr = {0, 1, 0, -1};
    static int[] dc = {-1, 0, 1, 0};

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        grid = new int[N + 4][N + 4];//가장자리부분만 따로더한다.
        for (int i = 2; i < N + 2; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 2; j < N + 2; j++) {
                grid[i][j] = Integer.parseInt(st.nextToken());
            }
        }
        int sr = N / 2 + 1 + 2 - 1;
        int sc = N / 2 + 1 + 2 - 1;
        int d = 0;
        loop:
        while (sr >= 2 && sc >= 2 && sr <= N - 1 && sc <= N - 1) {//토네이도 위치 그리드 내부일때
            for (int k = 1; k <= N; k++) {
                //두번씩 k칸이동
                for (int i = k == N ? 2 : 1; i <= k; i++) {//마지막 행일떄는 한칸 덜 가야함
                    sr += dr[d];
                    sc += dc[d];
                    tornado(sr, sc, d);
                    grid[sr][sc] = 0;
                }

                d = directionPlus(d + 1);
                if (k == N) break loop;//마지막시행 종료

                for (int i = 1; i <= k; i++) {
                    sr += dr[d];
                    sc += dc[d];
                    tornado(sr, sc, d);
                    grid[sr][sc] = 0;
                }

                d = directionPlus(d + 1);

            }
        }
        int answer = 0;
        for (int i = 0; i < N + 4; i++) {
            System.out.println();
            for (int j = 0; j < N + 4; j++) {
                System.out.print(grid[i][j] + "  ");
                if (i >= 2 && j >= 2 && i <= N + 1 && j <= N + 1) continue;
                answer += grid[i][j];
            }
        }
        System.out.println("\n\n" + answer);
    }

    static void tornado(int sr, int sc, int d) {
        int sand = grid[sr][sc];
        if (sand == 0) return;

        int comsumed = 0;
        //위두개---------------------
        int newdr = directionPlus(d + 3);
        int newdc = directionPlus(d + 3);
        comsumed += (int) (sand * 0.07);
        grid[sr + dr[newdr]][sc + dc[newdc]] += (int) (sand * 0.07);
        comsumed += (int) (sand * 0.02);
        grid[sr + 2 * dr[newdr]][sc + 2 * dc[newdc]] += (int) (sand * 0.02);
        //위오른쪽
        newdr = directionPlus(d + z);
        newdc = directionPlus(d + 2);
        comsumed += (int) (sand * 0.01);
        grid[sr + dr[newdr]][sc + dc[newdc]] += (int) (sand * 0.01);
        //위왼쪽
        newdr = directionPlus(d + 3);
        newdc = directionPlus(d);
        comsumed += (int) (sand * 0.10);
        grid[sr + dr[newdr]][sc + dc[newdc]] += (int) (sand * 0.10);
        //아래두개---------------------
        newdr = directionPlus(d + 1);
        newdc = directionPlus(d + 1);
        comsumed += (int) (sand * 0.07);
        grid[sr + dr[newdr]][sc + dc[newdc]] += (int) (sand * 0.07);
        comsumed += (int) (sand * 0.02);
        grid[sr + 2 * dr[newdr]][sc + 2 * dc[newdc]] += (int) (sand * 0.02);
        //아래오른쪽
        newdc = directionPlus(d + 2);
        comsumed += (int) (sand * 0.01);
        grid[sr + dr[newdr]][sc + dc[newdc]] += (int) (sand * 0.01);
        //아래왼쪽
        newdc = directionPlus(d);
        comsumed += (int) (sand * 0.10);
        grid[sr + dr[newdr]][sc + dc[newdc]] += (int) (sand * 0.10);

        //왼왼쪽---------------
        comsumed += (int) (sand * 0.05);
        grid[sr + 2 * dr[d]][sc + 2 * dc[d]] += (int) (sand * 0.05);

        grid[sr + dr[d]][sc + dc[d]] += sand - comsumed;
    }

    static int directionPlus(int newd) {
        return (newd + 4) % 4;
    }
}

 

아래는 모든 방향에 따른 모래가 퍼지는 방향을 정의해놓은 후에 작성한 코드이다.

 

코드출처 : https://alwaysbemoon.tistory.com/225

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;

public class Main {
    static int N;
    static int[][] map;
    static int[] dx = {0, 1, 0, -1};   //토네이토의 x 이동 방향
    static int[] dy = {-1, 0, 1, 0};   //토네이토의 y 이동 방향
    static int[] dc = {1, 1, 2, 2};   // 토네이도의 각 방향으로 이동하는 횟수
    static int[][] dsx = {
            {-1, 1, -2, -1, 1, 2, -1, 1, 0},
            {-1, -1, 0, 0, 0, 0, 1, 1, 2},    //모래가 퍼지는 x방향
            {1, -1, 2, 1, -1, -2, 1, -1, 0},
            {1, 1, 0, 0, 0, 0, -1, -1, -2}
    };
    static int[][] dsy = {
            {1, 1, 0, 0, 0, 0, -1, -1, -2},
            {-1, 1, -2, -1, 1, 2, -1, 1, 0},    //모래가 퍼지는 y방향
            {-1, -1, 0, 0, 0, 0, 1, 1, 2},
            {1, -1, 2, 1, -1, -2, 1, -1, 0}
    };
    static int[] sandRatio = {1, 1, 2, 7, 7, 2, 10, 10, 5};

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st;

        N = Integer.parseInt(br.readLine().trim());
        map = new int[N][N];

        for (int r = 0; r < N; r++) {
            st = new StringTokenizer(br.readLine(), " ");
            for (int c = 0; c < N; c++) {
                map[r][c] = Integer.parseInt(st.nextToken());
            }
        }

        int result = calculateOutSand(N / 2, N / 2);
        bw.write(String.valueOf(result));
        bw.flush();


    }

    //현재위치에서 이동 -> 이동한 위치의 모래 뿌리기 -> 이동한위치를 현재위치로 업데이트
    static int calculateOutSand(int x, int y) {
        int totalOutSand = 0;

        int currentX = x;
        int currentY = y;

        while (true) {
            for (int d = 0; d < 4; d++) {
                for (int moveCount = 0; moveCount < dc[d]; moveCount++) {
                    //현재위치에서 이동
                    int nextX = currentX + dx[d];
                    int nextY = currentY + dy[d];

                    if (nextX < 0 || nextY < 0 || nextX >= N || nextY >= N) {
                        return totalOutSand;
                    }

                    //이동한 위치의 모래 뿌리기
                    int sand = map[nextX][nextY];
                    map[nextX][nextY] = 0;
                    int spreadTotal = 0;


                    for (int spread = 0; spread < 9; spread++) {
                        int sandX = nextX + dsx[d][spread];
                        int sandY = nextY + dsy[d][spread];
                        int spreadAmount = (sand * sandRatio[spread]) / 100;

                        if (sandX < 0 || sandX >= N || sandY < 0 || sandY >= N) {
                            totalOutSand += spreadAmount;
                        } else {
                            map[sandX][sandY] += spreadAmount;
                        }
                        spreadTotal += spreadAmount;
                    }

                    //알파
                    int alphaX = nextX + dx[d];
                    int alphaY = nextY + dy[d];
                    int alphaAmount = sand - spreadTotal;
                    if (alphaX < 0 || alphaX >= N || alphaY < 0 || alphaY >= N) {
                        totalOutSand += alphaAmount;
                    } else {
                        map[alphaX][alphaY] += alphaAmount;
                    }


                    //이동한 위치를 현재위치로 업데이트
                    currentX = nextX;
                    currentY = nextY;
                }
            }

            //횟수 업데이트
            for (int index = 0; index < 4; index++) {
                dc[index] += 2;
            }
        }
    }

}
반응형