티스토리 뷰

문제

 

1463번: 1로 만들기

첫째 줄에 1보다 크거나 같고, 106보다 작거나 같은 정수 N이 주어진다.

www.acmicpc.net

해결 과정

단계별로 풀어보기 중 동적 계획법(Dynamic Programming)에 나온 문제라서 우선 동적 계획법을 시도했다. 당시에는 구하고자 하는 수에서 부터 1로 계산해가는 방식을 사용하려고 했는데 구현 과정에서 막혔다.

BFS를 이용해서 처음 n에 도달하면 탐색을 종료하는 방법을 떠올리고 시도해 보았지만 BFS를 구현한 적이 없어서 실력 부족으로 역시 실패했다.

결국 생각을 바꿔 동적 계획법으로 1부터 n까지 계산해가며 쌓아올리는 방식으로 구현해냈다. 아래는 성공한 결과물이다.

#include <stdio.h>
inline int min(int a, int b) {return a < b ? a : b;}

int main() {
    int n, *dp;
    scanf("%d", &n);
    dp = new int[n+1];
    
    for(int i = 2; i <= n; i ++) {
        if (i%3 == 0) {
            dp[i] = min(dp[i/3], dp[i-1]) + 1;
            if (i%2 == 0)
                dp[i] = min(dp[i] - 1, dp[i/2]) + 1;
        } else if (i%2 == 0) {
            dp[i] = min(dp[i-1], dp[i/2]) + 1;
        } else
            dp[i] = dp[i-1] + 1;
    }
    
    printf("%d\n", dp[n]);
    
}

결과

메모리를 꽤 많이 차지했다.

결과는 살짝 아쉬웠다.

실행 시간은 만족스러운 정도였지만 배열의 크기가 최대 1000000를 차지하는 만큼 메모리를 많이 소모했다.

회고

이후 다른 코드를 보던 중 엄청 기발한 코드를 발견했다.

메모리도 덜 차지하고 실행 시간도 0ms이다.

#include <stdio.h>

int func(int n)
{
	int a, b;
	if (n < 2)
		return 0;
	a = func(n / 2) + n % 2 + 1;
	b = func(n / 3) + n % 3 + 1;
	if (a < b)
		return a;
	else
		return b;
}

int main(void)
{
	int n;

	scanf("%d", &n);
	
	printf("%d\n", func(n));

	return 0;
}

핵심은 a와 b에 값을 할당하는 부분이다. 나누어 떨어지는 지의 여부 확인과 -1 연산을 분리시키는 연산을 통합해 나머지를 더하는 연산으로 바꿨다. 이럴 경우 n이 2나 3씩 나누어지는 만큼 함수의 호출이 줄고 조건 연산도 적어지기 때문에 실행 시간을 획기적으로 줄인다.

다만 현재 연습하고 있는 동적 계획법을 사용한 방법은 아니기 때문에 이런 창의적인 방법이 있다는 것 정도로 알아두면 될 것 같다.

'공부한 것들 > 알고리즘' 카테고리의 다른 글

[백준] 18870 - 좌표 압축  (0) 2020.04.20
[백준] 9251 - LCS  (0) 2020.02.07
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함