[백준] java 11866 요세푸스 문제 0

Sundae·2023년 12월 26일
0

백준

목록 보기
47/63
post-thumbnail
post-custom-banner

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


문제

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

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)

풀이과정

두 개의 큐 자료구조를 사용하면 쉽게 풀이가 가능할 것 같다.

처음 구상한 방법은 큐 두개를 준비한 다음, 큐 A에 원소를 전부 삽입한다. 그리고 큐 A에서 원소를 pop하며 큐 B에 삽입한다. 이때, K 번째 원소는 큐 A에 삽입하지 않고 요세푸스 순열에 추가한다.

위와 같이 큐 A가 빌 때까지 큐 B로 원소를 pop하면서 요세푸스 순열을 채워나간다. 큐 A가 비게되면 이번엔 큐 B에서 큐 A로 원소를 pop하며 요세푸스 순열을 추가해나간다.

위와 같은 단계로 큐 A와 큐 B 모두 원소가 하나도 남지 않게 되었을 때까지 반복하면 요세푸스 순열을 알 수 있을 것이다.

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");
        
        int N = Integer.parseInt(st.nextToken());
        int K = Integer.parseInt(st.nextToken());
		// 큐 A
        CustomLinkedList QueueA = new CustomLinkedList();
        // 큐 B
        CustomLinkedList QueueB = new CustomLinkedList();
        // 1부터 N까지 원소 추가
        for( int i = 1; i <= N; i++ )
            QueueA.add(i);

        sb.append("<");
        int count = 1;
        // 큐 A가 비어있지 않다면 true
        // 큐 A가 비어있다면 큐 B로부터 원소를 받아야하기 때문에
        // false로 변경
        boolean currentQueue = true;
        // 큐 A와 큐 B에 원소가 하나도 남지 않게 될 때까지 반복
        while( true ){
			// 큐 A가 비어있지 않다면
            if( currentQueue ){
				// count가 K로 나누어 떨어지지 않는다면
                // pop한 원소를 QueueB에 추가
                if( count % K != 0 ){
                    QueueB.add(QueueA.pop().value);
                }
                // count가 K로 나누어 떨어지면 
                // 요세푸스 순열에 추가
                else{
                    sb.append(QueueA.pop().value).append(", ");
                }
                // 큐 A가 비어있다면 currentQueue를
                // false로 변경
                if( QueueA.size == 0 )
                    currentQueue = !currentQueue;

            }
            // 큐 A가 비어있다면 else 로직 수행
            else {
				
                if( count % K != 0 ){
                    QueueA.add(QueueB.pop().value);
                }else{
                    sb.append(QueueB.pop().value).append(", ");
                }

                if( QueueB.size == 0 )
                    currentQueue = !currentQueue;

            }
			// QueueA와 QueueB에 원소가 하나도 없다면
            // 모든 요세푸스 순열을 완성하였으므로 반복문 종료
            if( QueueA.size == 0 && QueueB.size == 0 )
                break;

            count++;
        }
        // 마지막 쉼표와 공백 제거
        sb.delete(sb.length()-2,sb.length());
        sb.append(">");
        System.out.println(sb);
    }

아래 코드는 직접 구현한 이중 연결 리스트이다. 본 문제에선 삭제와 삽입이 빈번하게 이루어지기 때문에 연결 리스트를 사용하는 것이 유리할 것이라 생각했다.

    static class CustomLinkedList{
        Node firstNode;
        Node lastNode;
        int size;
        public CustomLinkedList(){
            firstNode = null;
            lastNode = null;
            size = 0;
        }
        public void add( int num ){
            if( firstNode == null ){
                Node node = new Node( num );
                firstNode = node;
                lastNode = node;
            }else {
                Node node = new Node( num );
                lastNode.nextNode = node;
                lastNode = node;
            }
            size++;
        }
        public Node pop(){
            if( firstNode == null )
                return null;
            Node node = firstNode;
            firstNode = firstNode.nextNode;
            size--;
            return node;
        }
    }
    static class Node{
        int value;
        Node nextNode;
        Node( int value ){
            this.value = value;
            nextNode = null;
        }
    }
}
profile
성장 기록 / 글에 오류가 있다면 댓글 부탁드립니다.
post-custom-banner

0개의 댓글