안녕하세요,
이 글에서는 BOJ 의 20921번 그렇고 그런 사이 문제를 풀이하려고 합니다.
문제 정보는 아래 북마크를 통해 확인하실 수 있습니다.
https://www.acmicpc.net/problem/20921
20921번: 그렇고 그런 사이
정수 $N$, $K$가 주어진다. ($2 \leq N \leq 4\,242$, $0 \leq K \leq \frac{N(N-1)}{2}$)
www.acmicpc.net
해당 문제는
'1부터 n까지의 배열을,
배열에서 왼쪽에 있는 수가 오른쪽에 있는 수보다 큰 경우가
k개가 되도록 변형하는 문제'
로 요약할 수 있습니다.
예를 들어 k가 2인 경우, 왼쪽에 있는 배열은 오른쪽에 있는 배열로 바뀔 수 있습니다.

이때 오른쪽 배열에서, 왼쪽에 있는 수가 오른쪽에 있는 수보다 큰 경우를 찾아보면,
(3, 1), (3, 2)
로 2가지가 존재합니다.
문제를 이해하였으니,
다음으로 고민할 것은 '배열을 어떻게 바꾸어야 k개가 될 것인가'입니다.
저는 여기서 다음과 같은 특성을 이용하였습니다.

배열 [ 1, 2, 3, 4 ] 에서,
2보다 작은 원소는 1이므로, 왼쪽에 있는 2가 오른쪽에 있는 수보다 큰 경우는 최대 1가지입니다.
3보다 작은 원소는 1, 2이므로, 왼쪽에 있는 3이 오른쪽에 있는 수보다 큰 경우는 최대 2가지입니다.
4보다 작은 원소는 1, 2, 3이므로, 왼쪽에 있는 4가 오른쪽에 있는 수보다 큰 경우는 최대 3가지입니다.
이처럼 n을 다른 n-1개의 수보다 앞쪽으로 이동시킬 경우,
왼쪽에 있는 수가 오른쪽에 있는 수보다 큰 경우가 n-1개 발생합니다.
(n-1개의 수가 어떤 순서로 있더라도 성립합니다.)
따라서 만약 배열 [ 1, 2, 3, 4, 5 ] 이 주어지고 k가 7이라면,
5를 첫 번째 위치로 이동하여 원하는 경우가 4개 발생하도록 하고,
4를 두 번째 위치로 이동하여 원하는 경우가 3개 발생하도록 하여,
총 7개가 되도록 변형할 수 있습니다.

이를 토대로 다음과 같은 소스 코드를 작성하여 통과하였습니다.
#include <stdio.h>
#define MAX 4245 // 2 <= N <= 4242
int n, k, changed_num=0;
int original[MAX], changed[MAX]; // original : 원래 배열, changed : 변형한 배열
int main() {
// 정수의 개수 n과 경우의 개수 k를 입력받는다.
scanf("%d %d", &n, &k);
// 원래 배열을 만든다. (만약 n이 5라면, 배열 { 1, 2, 3, 4, 5 } 을 만든다.)
for (int i=0; i<n; i++)
original[i] = i + 1;
// i를 n-1부터 1로 줄여가면서, k가 i보다 크다면
// k에서 i를 빼고 배열의 앞쪽에 i+1을 저장한다.
// (이 과정을 통해 n=5이고 k=7이라면, k는 4+3으로 분해된다.)
// (이와 동시에 i가 4일 때 배열의 첫 번째에 5가, i가 3일 때 배열의 두 번째에 4가 위치하게 된다.)
// (그 결과 배열 original는 { 1, 2, 3, -1, -1 }이 되고, 배열 changed는 { 5, 4, ?, ?, ? }이 된다.)
for (int i=n-1; i>0; i--) {
if (k >= i) {
k -= i;
original[i] = -1;
changed[changed_num++] = i+1;
}
}
// 배열 changed를 앞에서부터 출력한다.
// 이 때 배열 original에서 -1이 아닌 원소를 배열 changed에 차례대로 옮긴다.
// (그 결과 배열 changed는 { 5, 4, 1, 2, 3 } 이 된다.)
for (int i=0; i<n; i++) {
if (original[i] >= 0)
changed[changed_num++] = original[i];
printf("%d ", changed[i]);
}
printf("\n");
return 0;
}
다소 급하게 작성한 코드라, 이해가 어려우실까봐 걱정이 됩니다.
주석을 자세하게 달아놓았지만, 막히는 부분이 있다면 댓글로 얼마든지 질문해주세요.
감사합니다.
'기본' 카테고리의 다른 글
| [코딩테스트/개념] 크루스칼 알고리즘 (Kruskal's Algorithm) (0) | 2024.03.28 |
|---|---|
| [코딩테스트/Python] 프로그래머스 "체육복" (0) | 2024.03.27 |
| [코딩테스트/개념] 탐욕 알고리즘 (Greedy Algorithm) (0) | 2024.03.27 |
| [코딩테스트/Python] 프로그래머스 "퍼즐 조각 채우기" (0) | 2024.03.27 |
| [코딩테스트/Python] 프로그래머스 "아이템 줍기" (0) | 2024.03.26 |