본문 바로가기

문제풀이

BOJ 1071 소트

728x90

문제

N개의 정수가 주어지면, 이것을 연속된 두 수가 연속된 값이 아니게 정렬(A[i] + 1 ≠ A[i+1])하는 프로그램을 작성하시오. 가능한 것이 여러 가지라면 사전순으로 가장 앞서는 것을 출력한다.

입력

첫째 줄에 N이 주어진다. N은 50보다 작거나 같은 자연수이다. 둘째 줄에는 N개의 수가 주어진다. N개의 수는 1,000보다 작거나 같은 자연수 또는 0이다.

출력

첫째 줄에 문제의 정답을 출력한다.

예제 입력 1

3 1 2 3

예제 출력 1

1 3 2

예제 입력 2

9 1 1 1 1 2 2 2 2 2

예제 출력 2

2 2 2 2 2 1 1 1 1

풀이

이 문제는 재귀함수를 사용해 쉽게 풀 수 있다. 우선 N개 수 중 P개의 수를 배열했다고 할 때, 나머지를 배열하는 방법은 P+1번째 수에 쓸 수 있는 가장 작은 수를 쓰고, 그렇게 하는 것이 불가능하다면 그 다음으로 작은 수를 쓰는 방식으로 풀 수 있다.

 

여기서 n번째로 작은 수를 찾는 방법은 입력으로 들어온 수를 작은것부터 큰것까지 배열에 저장하면 된다.

 

배열의 숫자가 0인 경우도 있으니 이를 유의하여 코드를 짜야 한다. 모든 배열의 수에 1을 더한 후 답을 구하고, 답 배열의 모든 원소에서 1을 뺀 배열을 출력할 수도 있다.

소스코드

#include <stdio.h>

#define MAX 1010

int arr[MAX];
int set[MAX];
int cur[MAX];
int res[MAX];

int f(int level, int N, int M)
{
	int i;
	int ret;
	if (level > N)
	{
		for (i = 1; i <= N; i++)
		{
			res[i] = cur[i];
		}
		return 1;
	}
	else
	{
		for (i = 1; i <= M; i++)
		{
			if ((arr[set[i]] != 0) && (cur[level - 1] + 1 != set[i]))
			{
				arr[set[i]]--;
				cur[level] = set[i];
				ret = f(level + 1, N, M);
				if (ret == 1)
				{
					return 1;
				}
				arr[set[i]]++;
				cur[level] = 0;
			}
		}
		return 0;
	}
}

int main()
{
	int N;
	scanf("%d", &N);

	int i;
	int a;

	for (i = 1; i <= N; i++)
	{
		scanf("%d", &a);
		arr[a + 1]++;
	}
	
	int ptr = 0;

	for (i = 1; i <= 1002; i++)
	{
		if (arr[i] != 0)
		{
			set[++ptr] = i;
		}
	}

	cur[0] = -MAX;
	f(1, N, ptr);

	for (i = 1; i <= N; i++)
	{
		printf("%d ", res[i] - 1);
	}
	printf("\n");

	return 0;
}
728x90

'문제풀이' 카테고리의 다른 글

백준 15261 Donut Drone (CERC 2017 D)  (0) 2021.08.19
백준 16977 히스토그램에서 가장 큰 직사각형과 쿼리  (0) 2021.04.19
BOJ 1017 소수 쌍  (0) 2020.10.28
BOJ 1321 군인  (0) 2020.10.27
BOJ 1849 순열  (0) 2020.10.27