알고리즘/백준

BOJ) 체스판 위의 공

Zin0_0 2020. 7. 11. 20:55
반응형

체스판 위의 공

 

16957번: 체스판 위의 공

크기가 R×C인 체스판이 있고, 체스판의 각 칸에는 정수가 하나씩 적혀있다. 체스판에 적혀있는 정수는 모두 서로 다르다. 체스판의 각 칸 위에 공을 하나씩 놓는다. 이제 공은 다음과 같은 규칙��

www.acmicpc.net

풀이

 

체스판의 크기가 500x500이지만, 공들이 옮겨가면서 0인 부분이 많이 생길거라고 생각하고 DFS로 진행했다.

하지만, 6%에서 시간초과가 떴고 DFS로는 풀 수 없는 문제라고 생각이 들었다.

그래서 인접한 칸들 중 가장 작은 숫자로 이동한다는 조건을 보고, find-union을 응용하면 풀 수 있을거라고 생각했다.

 

일단, union부분은 필요가 없다고 생각을 했다.

생각하기도 복잡해지고, 타고 타고 이동해야하는 특성상 parents만 조정하기로 했다.

 

우선, 맵을 돌면서 각 지점마다 현재의 칸과 인접한 칸 중 가장 작은 칸으로 parents를 설정해주었다.

2차원 배열은 좌표를 저장하기가 애매해져서, 모든 칸에 인덱스를 부여해서 관리했다.

또한, 설정을 할 때, dfs를 통해서 저장해줬다.

 

저장이 끝난 이후에는, 저장된 parents를 타면서 find 된 가장 parent 부분에 값을 증가시키면서 이동된 구슬의 값을 저장했다.

 

위의 과정 마저 끝나면, 모든 좌표를 돌면서 StringBuffer에 값을 담아 출력을 준비했다.

 

3번의 과정을 돌면서, 답을 구할 수 있었다.

 

 

 

 

시간초과 코드 (DFS)

 

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

public class Main {
    final static int[] dx = {0,1,1,1,0,-1,-1,-1}, dy = {-1,-1,0,1,1,1,0,-1};
    final static int MAX_VALUE = 300001;
    static int maxY, maxX;
    static int[][] balls;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        maxY = Integer.parseInt(st.nextToken());
        maxX = Integer.parseInt(st.nextToken());

        int[][] map = new int[maxY][maxX];
        balls = new int[maxY][maxX];

        for(int i=0; i<maxY; i++) {
            st = new StringTokenizer(br.readLine());
            for(int j=0; j<maxX; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
                balls[i][j] = 1;
            }
        }

        solution(map);
        br.close();
    }

    private static void solution(int[][] map) {
        StringBuffer sb = new StringBuffer();
        final String space = " ", newLine = "\n";
        for(int y=0; y<maxY; y++) {
            for(int x=0; x<maxX; x++) {
                if(balls[y][x] !=0) {
                    dfs(x,y,map);
                }
            }
        }

        for(int y=0; y<maxY; y++) {
            for(int x=0; x<maxX; x++) {
                sb.append(balls[y][x]).append(space);
            }
            if(y <maxY-1) { sb.append(newLine); }
        }
        System.out.println(sb.toString());
    }

    private static void dfs(int x, int y, int[][] map) {
        int min = MAX_VALUE;
        int minX=0, minY=0;

        for(int i=0; i<8; i++) {
            int nx = x+dx[i];
            int ny = y+dy[i];
            if(isInArea(nx,ny)) {
                if(min > map[ny][nx]) {
                    min = map[ny][nx];
                    minX = nx;
                    minY = ny;
                }
            }
        }
        if(min < map[y][x]) {
            balls[minY][minX] += balls[y][x];
            balls[y][x] =0;
            dfs(minX, minY, map);
        }
    }

    private static boolean isInArea(int x, int y) {
        return x>=0 && x<maxX && y>=0 && y<maxY;
    }
}

 

통과 코드 (find-union)

 

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

public class Main {
    final static int[] dx = {0,1,1,1,0,-1,-1,-1}, dy = {-1,-1,0,1,1,1,0,-1};
    final static int MAX_VALUE = 300001;
    static int maxY, maxX;
    static int[] parents;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        maxY = Integer.parseInt(st.nextToken());
        maxX = Integer.parseInt(st.nextToken());

        int[][] map = new int[maxY][maxX];
        parents = new int[maxY*maxX];

        for(int i=0; i<maxY; i++) {
            st = new StringTokenizer(br.readLine());
            for(int j=0; j<maxX; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
                parents[i*maxX+j] = i*maxX+j;
            }
        }

        solution(map);
        br.close();
    }

    private static void solution(int[][] map) {
        StringBuffer sb = new StringBuffer();
        final String space = " ", newLine = "\n";
        for(int y=0; y<maxY; y++) {
            for(int x=0; x<maxX; x++) {
                if(parents[y*maxX+x] ==y*maxX+x) {
                    dfs(x,y,map);
                }
            }
        }

        int mul = maxX*maxY;
        int[] answer = new int[mul];

        for(int i=0; i<mul; i++) {
            answer[find(i)]++;
        }

        for(int y=0; y<maxY; y++) {
            for(int x=0; x<maxX; x++) {
                sb.append(answer[y*maxX+x]).append(space);
            }
            sb.append(newLine);
        }
        System.out.println(sb.toString());
    }

    private static int find(int val) {
        if(val == parents[val]) { return val; }
        return parents[val] = find(parents[val]);
    }

    private static void dfs(int x, int y, int[][] map) {
        int min = MAX_VALUE;
        int minX=0, minY=0;

        for(int i=0; i<8; i++) {
            int nx = x+dx[i];
            int ny = y+dy[i];
            if(isInArea(nx,ny)) {
                if(min > map[ny][nx]) {
                    min = map[ny][nx];
                    minX = nx;
                    minY = ny;
                }
            }
        }
        if(min < map[y][x]) {
            if(parents[y*maxX+x] == maxX*y+x) {
                parents[y*maxX+x] = minY * maxX + minX;
                dfs(minX, minY, map);
            }
        }
    }

    private static boolean isInArea(int x, int y) {
        return x>=0 && x<maxX && y>=0 && y<maxY;
    }
}

 

반응형