문제 출저
https://www.acmicpc.net/problem/1722
1722번: 순열의 순서
첫째 줄에 N(1 ≤ N ≤ 20)이 주어진다. 둘째 줄의 첫 번째 수는 소문제 번호이다. 1인 경우 k(1 ≤ k ≤ N!)를 입력받고, 2인 경우 임의의 순열을 나타내는 N개의 수를 입력받는다. N개의 수에는 1부터 N
www.acmicpc.net
문제 풀이
이 문제는 2가지 문제를 풀어야 합니다.
첫 번째 입력은 n이 주어지고 두 번째 입력의 첫 번째 숫자는 어떤 문제를 풀어야 하는지 타입입니다.
1인 경우, k가 주어지며 k번째 순열을 구해야 합니다.
2인 경우, 순열이 주어지며 이 순열이 몇 번째 순서인지 구해야 합니다.
문제의 n은 20이므로 일일히 다 순열을 구하면 20! 이 되므로 시간초과가 발생합니다.
간격을 통해서 문제를 풀어야 합니다.
먼저, int[] factorial 을 n-1 크기로 만들어 1!, 2!, 3! 같이 각 수의 팩토리얼을 구합니다.
문제 유형이 2번인 경우에 n = 4, int[] permutation = {1,3,2,4}가 주어졌을 때 예를 들어보겠습니다.
각 자리의 숫자가 오기 까지 factorial[n-i-1] 반복됩니다.
이게 무슨 말이냐면 1번째 자리인 1이 오기까진 factorial[4 - 0 - 1] * 0 이 반복된 것 입니다.
2번째 자리인 3이 오기까진 factorial[4 - 1 - 1] * 2이 반복된 것 입니다.
이렇게 각 자리수가 오기까지의 횟수를 구하고 1부터 시작했기에 1을 더하면 문제를 풀 수 있습니다.
1번 문제인 경우, 2번 문제를 반대로 풀면 구할 수 있습니다.
저는 해당 블로그의 글을 참고했습니다.
https://dundung.tistory.com/60
백준 1722 순열의 순서 Java
순열의 크기 N이 주어지고 순열이 사전순으로 정렬되어 있을 때 1번과 2번으로 나눈 문제가 주어진다. 1번의 경우에는 순열의 순서 k를 주고 k번째 순열 N개를 출력하면 된다. 2번의 경우에는 순열
dundung.tistory.com
소스 코드
package baekjoon.backjoon12.day0110.day08;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
/*
순열의 순서
https://www.aczmicpc.net/problem/1722
20! 이라 일일이 구하면 시간 초과가 발생한다.
참고 사이트
https://dundung.tistory.com/60
*/
public class B1722 {
static int n;
static int type;
static long[] factorial;
static boolean[] check;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
n = Integer.parseInt(br.readLine());
StringTokenizer st = new StringTokenizer(br.readLine());
type = Integer.parseInt(st.nextToken());
factorial = new long[n+1];
makeFactorial(n);
check = new boolean[n+1];
if(type == 1) {
long index = Long.parseLong(st.nextToken());
one(index);
}
else if(type == 2) {
int[] numbers = new int[n];
for(int i = 0; i < n; i++) {
numbers[i] = Integer.parseInt(st.nextToken());
}
two(numbers);
}
}
// 몇 번째인지 주어지고 순열이 뭔지 구해야한다.
public static void one(long index) {
int[] numbers = new int[n];
for(int i = 0; i < n; i++) {
for(int j = 1; j <= n; j++) {
// 이미 사용되었으면 넘어간다.
if(check[j]) continue;
// 이 자리의 숫자가 들어갈 수 있다면 뺀다.
if(factorial[n-i-1] < index) {
index -= factorial[n-i-1];
}
else {
numbers[i] = j;
check[j] = true;
break;
}
}
}
for(int i = 0; i < n; i++) {
System.out.print(numbers[i] + " ");
}
}
// 순열이 주어지고 몇 번째 인지 구해야 함
public static void two(int[] numbers) {
long index = 1;
for(int i = 0; i < n; i++) {
for(int j = 1; j < numbers[i]; j++) {
if(check[j] == false) {
index += factorial[n-i-1];
}
}
check[numbers[i]] = true;
}
System.out.println(index);
}
public static void makeFactorial(int n) {
factorial[0] = 1;
for(int i = 1; i <= n; i++) {
factorial[i] = factorial[i-1] * i;
}
}
}