본문 바로가기

백준/JAVA

[Baekjoon/JAVA] 11866번 - 요세푸스 문제 0

Baekjoon Online Judge

문제로 이동

 

문제

요세푸스 문제는 다음과 같다.

1번부터 N번까지 N명의 사람이 원을 이루면서 앉아있고, 양의 정수 K(≤ N)가 주어진다. 이제 순서대로 K번째 사람을 제거한다. 한 사람이 제거되면 남은 사람들로 이루어진 원을 따라 이 과정을 계속해 나간다. 이 과정은 N명의 사람이 모두 제거될 때까지 계속된다. 원에서 사람들이 제거되는 순서를 (N, K)-요세푸스 순열이라고 한다. 예를 들어 (7, 3)-요세푸스 순열은 <3, 6, 2, 7, 5, 1, 4>이다.

N과 K가 주어지면 (N, K)-요세푸스 순열을 구하는 프로그램을 작성하시오.

 

입력

첫째 줄에 N과 K가 빈 칸을 사이에 두고 순서대로 주어진다. (1 ≤ K ≤ N ≤ 1,000)

 

출력

예제와 같이 요세푸스 순열을 출력한다.

 


예제 입력 예제 출력
7 3 <3, 6, 2, 7, 5, 1, 4>

풀이

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);

        Queue queue = new Queue();

        queue.max = in.nextInt(); // 사람의 수
        int K = in.nextInt(); // 양의 정수 K

        queue.init(); // 큐 초기화
        queue.print(K); // 형식에 맞게 출력
    }
}

class Queue {
    int max;

    int front;
    int rear;
    int[] data;

    // 큐 초기화
    void init() {
        front = 0;
        rear = 0;

        data = new int[max + 1];

        for (int i = 1; i <= max; i++)
            enqueue(i);
    }

    // 큐에 데이터 입력
    void enqueue(int n) {
        data[++rear % (max + 1)] = n;
    }

    // 큐에서 데이터 삭제
    int dequeue() {
        return data[++front % (max + 1)];
    }

    // 공백 여부 확인
    Boolean isEmpty() {
        return (front == rear);
    }

    // 형식에 맞게 출력
   void print(int k) {
        System.out.print("<");
        while(true) {
            for (int i = 1; i < k; i++)
                enqueue(dequeue());

            System.out.printf("%d", dequeue());

            if (!isEmpty())
                System.out.print(", ");
            else
                break;
        }
        System.out.println(">");
    }
}

원형큐를 이용해서 문제를 풀었다.

 

    // 큐 초기화
    void init() {
        front = 0;
        rear = 0;

        data = new int[max + 1];

        for (int i = 1; i <= max; i++)
            enqueue(i);
    }

큐를 초기화하는 코드이다. 1부터 입력한 숫자까의 숫자를 배열로 구현한 큐에 순서대로 입력한다.

 

    // 형식에 맞게 출력
   void print(int k) {
        System.out.print("<");
        while(true) {
            for (int i = 1; i < k; i++)
                enqueue(dequeue());

            System.out.printf("%d", dequeue());

            if (!isEmpty())
                System.out.print(", ");
            else
                break;
        }
        System.out.println(">");
    }

문제를 풀기 위해서는 init으로 큐를 초기화한 뒤 이 함수를 호출해야 한다. 원을 이루며 앉아있는 사람 중 K번째 사람을 제거하기 위해서는 K번째보다 앞에 있는 사람이 사라져서 K가 가장 앞에 있어야 한다. 이를 위해 K번째가 맨 앞에 위치할 때까지 dequeue()를 호출해서 큐에서 데이터를 삭제했다. 삭제한 데이터가 영영 없어지면 안되므로 그 데이터를 enqueue()를 통해 큐에 다시 저장했다. 그리고 K번째 사람을 dequeue()로 삭제한 뒤 이를 출력했다.

 

그 뒤 큐가 비어있는지를 확인했는데, 만약 큐가 비어있지 않다면 뒤에 더 숫자를 출력해야 하므로 ", "를 출력하도록 했으며, 큐가 비어있다면 반복문을 종료하게끔 했다.