ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • BOJ) 파이프 옮기기 1
    알고리즘/백준 2020. 7. 8. 19:37
    반응형

    파이프 옮기기 1

     

    17070번: 파이프 옮기기 1

    유현이가 새 집으로 이사했다. 새 집의 크기는 N×N의 격자판으로 나타낼 수 있고, 1×1크기의 정사각형 칸으로 나누어져 있다. 각각의 칸은 (r, c)로 나타낼 수 있다. 여기서 r은 행의 번호, c는 열의

    www.acmicpc.net

    풀이

     

    옮길 수 있는 모든 경우의 수를 찾는 문제기 때문에 브루트포스 문제다.

    직접 다 돌리는데는 BFS나 DFS만큼 편한게 없다고(?) 생각해서 DFS로 풀었다.

    문제를 풀면서 막혔던 부분은

     

    첫째로, 문제 조건을 잘못 이해했다는 것이다.

    파이프의 한쪽 끝을 (N, N)로 이동시키는 방법의 개수 

    이 문구에서 N,N을 보지 않고 N,y or x,N으로 이동한 파이프들을 구해줬었다...

     

    두번째로는 실수라기 보다는 기둥의 시작점인 (0,0)에서 시작했다는 것이다.

    편의상 기둥의 상단과 하단이 있다고 친다면, 처음 기둥의 상단이 0,0 에 하단이 1,0에 존재한다.

    여기서 상단을 기준으로 로직을 짰는데, 뭔가가 어긋났는지 잘 안됐다.

    그래서 하단인 (1,0)부터 시작을 해주고 조건을 바꿔주었다.

     

    위의 두 부분을 신경쓰니까 바로 통과됐다.

    dfs를 통해서 기둥이 N,N에 도달하는 지점 (코드에서 n-1,n-1에 도달하는 지점)을 찾아서 답을 구해주었고,

    가로,세로,대각선인 경우에 움직일 수 있는 방향을 switch문을 통해 지정해줬다.

     

    코드 1

    N이 3~16이나 돼서 효율이 좋지 못했다.

    하지만, 다른 방법은 딱히 떠오르지 않아서 다르게 풀어보는 것은 포기했다.

     

    대신 코드를 조금 더 줄이기 위해 if 문이 여러개 쓰이는 부분을 조금 수정해주었다.

    방향에 따라 움직이는 방법을 정해주는 부분은 for문을 통해서 바꿔줬고

    움직일 수 있는지 확인하는 canMove 부분의 if문을 줄이기 위해서, 가로 세로로 움직이는 horizon과 vertical 변수를 dx dy로 각 방향마다 다음 좌표로 움직일 수 있도록 설정해줬다.

     

    코드 2

    효율을 크게 좋지는 않지만, 코드 라인이 줄어든 것에 만족한다.

     

    코드 1

     

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.StringTokenizer;
    
    public class Main {
        final static int[] horizon = {1,0}, vertical = {0,1};
        final static int BLANK =0, WALL =1;
    
        static int answer, n, map[][];
    
        public static void main(String[] args) throws IOException {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            n = Integer.parseInt(br.readLine());
            map = new int[n][n];
    
            for(int i=0; i<n; i++) {
                StringTokenizer st = new StringTokenizer(br.readLine());
                for(int j=0; j<n; j++) {
                    map[i][j] = Integer.parseInt(st.nextToken());
                }
            }
            solution();
            br.close();
        }
    
        private static void solution() {
            answer =0;
            dfs(new PipePos(1,0,0)); // 끝 부분으로 시작하기
            System.out.println(answer);
        }
    
        private static void dfs(PipePos pipePos) {
            if(pipePos.x ==n-1 && pipePos.y == n-1) {
                answer++;
                return;
            }
            int dir = pipePos.direction;
            int x = pipePos.x;
            int y = pipePos.y;
            switch (dir) {
                case 0: // 가로, 대각선 가능
                    if(canMove(x,y,0)) {
                        dfs(new PipePos(x+horizon[0],y,0));
                    }
                    if(canMove(x,y,2)) {
                        dfs(new PipePos(x+horizon[0],y+vertical[1],2));
                    }
                    break;
                case 1: // 세로, 대각선 가능
                    if(canMove(x,y,1)) { dfs(new PipePos(x,y+vertical[1],1)); }
                    if(canMove(x,y,2)) { dfs(new PipePos(x+horizon[0],y+vertical[1],2)); }
                    break;
                case 2: // 가로, 세로, 대각선 가능
                    if(canMove(x,y,0)) { dfs(new PipePos(x+horizon[0], y, 0)); }
                    if(canMove(x,y,1)) { dfs(new PipePos(x,y+vertical[1],1)); }
                    if(canMove(x,y,2)) { dfs(new PipePos(x+horizon[0], y+vertical[1], 2)); }
                    break;
                default:
                    break;
            }
        }
    
        private static boolean canMove(int x, int y, int dir) {
            int nextX = x+horizon[0];
            int nextY = y+vertical[1];
            if(dir ==0) { // 가로
                if(nextX >=n) { return false; }
                if(map[y][nextX] == WALL) { return false; }
            } else if(dir ==1) { // 세로
                if(nextY >=n) { return false; }
                if(map[nextY][x] == WALL) { return false; }
            } else { // 대각선
                if (nextX >= n || nextY >= n) { return false; }
                if (map[nextY][nextX] == WALL || map[y][nextX] == WALL || map[nextY][x] == WALL) { return false; }
            }
            return true;
        }
    }
    
    class PipePos {
        int x;
        int y;
        int direction;  // 0 : 가로, 1 : 세로, 2 : 대각선
    
        public PipePos(int x, int y, int direction) {
            this.x =x;
            this.y =y;
            this.direction = direction;
        }
    }

     

    코드 2

     

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.StringTokenizer;
    
    public class Main {
        final static int[] dx = {1,0,1}, dy = {0,1,1};
        final static int WALL =1;
    
        static int answer, n, map[][];
    
        public static void main(String[] args) throws IOException {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            n = Integer.parseInt(br.readLine());
            map = new int[n][n];
    
            for(int i=0; i<n; i++) {
                StringTokenizer st = new StringTokenizer(br.readLine());
                for(int j=0; j<n; j++) {
                    map[i][j] = Integer.parseInt(st.nextToken());
                }
            }
            solution();
            br.close();
        }
    
        private static void solution() {
            answer =0;
            dfs(new PipePos(1,0,0)); // 끝 부분으로 시작하기
            System.out.println(answer);
        }
    
        private static void dfs(PipePos pipePos) {
            if(pipePos.x ==n-1 && pipePos.y == n-1) {
                answer++;
                return;
            }
            int dir = pipePos.direction;
            int x = pipePos.x;
            int y = pipePos.y;
            switch (dir) {
                case 0: // 가로, 대각선 가능
                    for(int i=0; i<3; i++) {
                        if(i != 1) {
                            if(canMove(x,y,i)) { dfs(new PipePos(x+dx[i], y+dy[i], i));}
                        }
                    }
                    break;
                case 1: // 세로, 대각선 가능
                    for(int i=1; i<3; i++) {
                        if(canMove(x,y,i)) { dfs(new PipePos(x+dx[i], y+dy[i], i)); }
                    }
                    break;
                case 2: // 가로, 세로, 대각선 가능
                    for(int i=0; i<3; i++) {
                        if(canMove(x,y,i)) { dfs(new PipePos(x+dx[i], y+dy[i], i));}
                    }
                    break;
                default:
                    break;
            }
        }
    
        private static boolean canMove(int x, int y, int dir) {
            int nx = x+dx[dir], ny = y+dy[dir];
            if(nx >=n || ny >=n) { return false; }
            if(map[ny][nx] == WALL) { return false; }
            if(dir ==2) {
                if(map[ny][x] == WALL || map[y][nx] == WALL) { return false; }
            }
            return true;
        }
    }
    
    class PipePos {
        int x;
        int y;
        int direction;  // 0 : 가로, 1 : 세로, 2 : 대각선
    
        public PipePos(int x, int y, int direction) {
            this.x =x;
            this.y =y;
            this.direction = direction;
        }
    }
    반응형

    '알고리즘 > 백준' 카테고리의 다른 글

    BOJ) 카드 구매하기  (0) 2020.07.08
    BOJ) 유기농 배추  (0) 2020.07.08
    BOJ) 인구 이동  (0) 2020.07.07
    BOJ) 에디터  (0) 2020.07.07
    BOJ) 쉬운 계단 수  (0) 2020.07.06

    댓글

Designed by Tistory.