문법/알고리즘

방향벡터, 돌아서 다시 처음으로(순회)

코딩 화이팅 2023. 3. 6. 13:34

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

 

10157번: 자리배정

첫 줄에는 공연장의 격자 크기를 나타내는 정수 C와 R이 하나의 공백을 사이에 두고 차례대로 주어진다. 두 값의 범위는 5 ≤ C, R ≤ 1,000이다. 그 다음 줄에는 어떤 관객의 대기번호 K가 주어진다.

www.acmicpc.net

//자리배정

package im대비;

import java.util.Scanner;

public class bj10157 {
    //상우하좌
    //지나가는 순서대로 델타배열 생성
    static int[] dy= {-1,0,1,0};
    static int[] dx= {0,1,0,-1};
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int X=sc.nextInt();//x크기
        int Y=sc.nextInt();//y크기
        int[][] map=new int[Y+2][X+2];
        //두칸씩 크게 해주는 이유
        //양옆과 위아래를 -1로 초기화해주고
        //좌표를 1,1부터 그대로 쓸 수 있기 때문에
        
        //위 아래를 -1로 초기화
        for (int i = 0; i < X+2; i++) {
            map[0][i]=-1;
            map[Y+1][i]=-1;
        }
        
        //양 옆을 -1로 초기화
        for (int i = 0; i < Y+2; i++) {
            map[i][0]=-1;
            map[i][X+1]=-1;
        }
        
        //만약 초과되는 값이 입력된다면 0출력
        int ans=sc.nextInt();
        if (ans>X*Y) {
            System.out.println("0");
        }
        
        //이제 돌아볼까
        int y=Y;//일단 비교 변수 선언하고 1,1부터 시작한다고 생각하고
        //입력한 값을 넣어줘야 좌표상에서 1,1이 되기 때문에 입력한 값 Y로 초기화
        int x=1;//x는 그대로 1,1일 때 1이기 때문에 그대로 1
        int count=1;//1부터 세줘야지
        int dir=0;//방향벡터에서 사용할 변수 처음은 위로 올라가기 때문에 0으로 초기화
        //나중에 while문 안에서 바꿔줄 예정
        while (true) {
            map[y][x]=count;//일단 지금 있는 좌표 값을 1로 선언
            if (map[y][x]==ans) {
                System.out.print(x+" "+(Y-y+1));//x는 해보니 다 값이 같았다.
                //뒤에 Y-y+1값을 찾아내는게 좀 어려웠다.
                //Y : 처음에 입력받은 위아래 값
                //y : 계속 바뀌는 위 아래 값
                //좌표상에서 y값은 2차배열에서의 위아래값과 반대이기 때문에
                //입력받은 Y값과 지금의 y값의 차이가 좌표 상에서의 y값
                //거기에 1을 더해주면 완벽한 좌표상의 y값이 된다.
                break;//찾았으니 일 멈춰
            }
            //만약 지금 값이 입력받은 값이다. 그러면 출력
            if (map[y+dy[dir]][x+dx[dir]]!=0) {
                dir=(dir+1)%4;
            }
            //만약 범위를 벗어나거나 이미 값이 있는 경우
            //지금의 dir은 4개가 있고
            //0 : 위
            //1 : 우
            //2 : 아래
            //3 : 좌
            //로 쓸 예정이다. 그래서 그 순서대로 나올 수 있게 만약 0으로 위로 가던 상화에서
            //위에 값이 있거나 범위를 벗어나는 경우(0이 아닌 경우) 1을 더해주면 1이 되고
            //그걸 4로 나눈 나머지는 역시 1
            //만약 왼쪽으로 (3)으로 가다가 왼쪽에 값이 있는 경우
            //위 수식대로 해준다면 0으로 다시 초기화 따라서 위 우 아래 좌 순서대로 쭉 갈 수 있다.
            x=x+dx[dir];
            y=y+dy[dir];
            //방향벡터 써서 초기화 된 dir값으로 x,y값을 바꿔준다.
            count++;
            //숫자는 계속 더해주고
            if (count>X*Y) {
                break;
            }
            //이제 더 이상 채워줄 곳이 없는 경우 혹시나의 익셉션을 방지하기 위해 걍 끝내버리자.
        }
    }
}

 

방향벡터에 대한 이해가 조금 될 수 있었고, 네가지의 방향이 있을 때 그것을 4로 나눠 원래대로 마지막에서 처음으로 쭉 돌아갈 수 있게 해준게 놀라웠다. 이렇게 방향에서 뿐만 아니라 다른 곳에서도 계속 돌아야 될 상황이 온다면 그 크기만큼 나누면 다시 처음으로 돌아올 수 있게 해주는 것을 쓰면 좋을 것 같다. 로직도 좋은 로직이라 몇 번 봐주면 좋을 것 같다.