본문 바로가기

알고리즘/백준알고리즘

[백준알고리즘-JAVA]11866번 풀이(요세푸스 문제) - 초보도 이해하는 풀이

안녕하세요

인포돈 입니다.

백준 알고리즘 11866번 풀이입니다. 

* 참고사항
 - 개발환경은 eclipse을 기준으로 작성되었습니다.
 - java언어를 이용하여 문제를 풀이합니다.
 - 알고리즘 문제는 풀이를 보고 해답을 찾는 것도 중요하지만 무엇보다 스스로 풀이를 시도해봐야 합니다!!
(해당 풀이를 보기 전 충분히 문제에 대해 고민해봐야 합니다!)
 - 해당 풀이 말고도 수많은 풀이 방법이 존재합니다.


백준 11866 (요세푸스 문제)

문제

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

 

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

입력

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

출력

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

입력 예제

7 3

출력 예제

<3, 6, 2, 7, 5, 1, 4>

성공코드

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

public class Main {

	static int N;
	static int K;
	static Deque<Integer> q = new LinkedList<>();
	static int count = 0;
	
	static StringBuilder sb = new StringBuilder();
	
	public static void main(String[] args) throws IOException {
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		N = Integer.parseInt(st.nextToken());
		K = Integer.parseInt(st.nextToken());	
		
		sb.append("<");
		
		for(int i = 1 ; i <=N ;i++) {
			q.add(i);
		}
		
		while(q.size()>1) {
			if(count == K-1) {
				sb.append(q.pop() + ", ");
				count = 0;
			} else {
				q.add(q.pop());
				count++;
			}
			
		}
		
		sb.append(q.pop()+">");
		
		System.out.println(sb);

		}
	
}

무 이번 요세푸스 문제는 간단히 풀 수 있는 문제였습니다. 간단히 주어진 K에 따라 변하는 알고리즘만 구축한다면 되거든요. 크게 어려울 것 없으니 STEP을 쉬엄쉬엄 보셔도 됩니다!


알고리즘 흐름도

입력받기 -> 1 ~ N까지 큐에 넣어주기 -> K에 따라 값 출력하기 -> 출력하기


STEP1 1 ~ N까지 큐에 넣어주기

뭐 없습니다. 반복문을 활용해 주세요

for(int i = 1 ; i <=N ;i++) {
			q.add(i);
		}

STEP2 어떻게 구현할지 구상하고 구현하기

간단합니다. K일 때마다 큐에서 해당 값을 POP 해주면 됩니다. 이때 K라는 순서를 가졌다는 것을 알려주기 위해 COUNT라는 변수를 사용해 줍니다.

		while(q.size()>1) {
			if(count == K-1) {
				sb.append(q.pop() + ", ");
				count = 0;
			} else {
				q.add(q.pop());
				count++;
			}
			
		}

저는 WHILE과 if문을 활용하여 구현하였고, k-1을 해준 이유는 count가 0부터 시작하기 때문이죠. 뭐 그렇게 안 하시려면 if문에 있는 count - 0;을 1로 바꿔주면 된답니다.

 

while q가 비어있을때까지 반복해라

 

if : 만약 k번쨰 순서의 숫자이면, 꺼내서 sb에 넣어줘라.

 

else : 만약 k 번쨰 순서의 숫자가 아니면 q의 첫 번째 값을 가지 마지막에 넣어주고 count를 1 증가해라

 

뭐 각자의 역할을 이정도로 생각하시면 되겠습니다~

 

*물론 LinkedList를 활용하는 게 좋고요 (큐를 구현할 때입니다.)

*저 같은 경우 deque를 사용하였는데 그냥 큐를 사용해도 문제없습니다!