모스 부호 사전

모스 부호 사전

n개의 장점과 m개의 단점으로 구성된 모든 신호들을 담고 있는 사전이 있다고 합시다. 예를 들어 n = m = 2라면 다음과 같은 신호들이 포함되어 있는 것이죠.

–oo
-o-o
-oo-
o–o
o-o-
oo–
이 신호들은 사전순서대로 정렬되어 있습니다. -의 아스키 코드는 45이고, o의 아스키 코드는 111이기 때문에 -가 먼저 오게 되죠. n과 m이 주어질 때 이 사전의 k번째 신호를 출력하는 프로그램을 작성해 봅시다. 예를 들어 위 사전에서 네 번째 신호는 o–o입니다..

4개의 신호로 이루어져있을 때 첫번째 코드가 ‘-‘ 이라면:

나머지 3개의 신호는 ‘-‘ 1개 ‘o’ 2개로 구성이되고 이때 만들 수 있는 신호의 가지 수를 구한다. 이때의 가지수가 k 보다 같거나 크다면 첫번째 신호는 ‘-‘ 으로 시작한다. 반대로 ‘-‘ 으로 시작하는 가지수보다 k가 크다면 ‘o’ 으로 시작함을 알 수 있다.

d[n+m][m]: n+m 개로 구성된 신호 중 m 개의 단점으로 구성된 신호 가지 수로 정의
첫 신호가 ‘-‘ 일 경우, 나머지 3가지 신호는 두번 째 신호가 ‘-‘ 일 경우와 아닌 경우로 나눌 수 있다.
d[2+2][2] = d[1+2][1] + d[1+2][2]

d[n+m][m] = d[n+m-1][m-1] + d[n+m-1][m]
즉, 조합 수와 같다: d[n][r] = d[n-1][r-1] + d[n-1][r]

4개 중 2개를 뽑는 경우의 수 = 6가지, 4C2 = 4! / (4-2)! * 2!
nCr = n! / ((n- r)! * k!)

// nCr = n-1Cr + n-1Cr-1
if (n == r || r == 0) {
    return 1;
}
1로 만들기

1로 만들기

정수 X에 사용할 수 있는 연산은 다음과 같이 세 가지 이다.
X가 3으로 나누어 떨어지면, 3으로 나눈다.
X가 2로 나누어 떨어지면, 2로 나눈다.
1을 뺀다.
정수 N이 주어졌을 때, 위와 같은 연산 세 개를 적절히 사용해서 1을 만들려고 한다. 연산을 사용하는 횟수의 최소값을 출력

10: 9 (-1) -> 3 (%3) -> 3 (%3) -> 1

d[n] = 연산 세 개로 1을 만드는 횟수의 최소값 정의

큰 수로 먼저 나누는게 이득인지 알 수 없다. 모든 경우의 수 중 최소값 택한다.

d[1] = 0
d[2] = 1 (%2 + d[1])
d[3] = 1 (%3 + d[1])
d[4] = 2 (%2 + d[2], -1 + d[3]])
d[5] = 3 (-1 + d[4])
d[6] = 2 (%3 + d[2], %2 + d[3], -1 + d[5])

d = new int[N+1];
Arrays.fill(d,  Integer.MAX_VALUE);
d[1] = 0;

for (int i = 2; i <= N; i++) {
    
    d[i] = Math.min(d[i], d[i-1] + 1);
    if (i % 2 == 0)
        d[i] = Math.min(d[i], d[i / 2] + 1);
    if (i % 3 == 0)
        d[i] = Math.min(d[i], d[i / 3] + 1);
}
크리보드

크리보드

크리보드는 kriii가 만든 신기한 키보드이다. 크리보드에는 버튼이 4개만 있으며, 하는 역할은 다음과 같다.
화면에 A를 출력한다.
Ctrl-A: 화면을 전체 선택한다
Ctrl-C: 전체 선택한 내용을 버퍼에 복사한다
Ctrl-V: 버퍼가 비어있지 않은 경우에는 화면에 출력된 문자열의 바로 뒤에 버퍼의 내용을 붙여넣는다.
크리보드의 버튼을 총 N번 눌러서 화면에 출력된 A개수를 최대로하는 프로그램을 작성하시오.

N = 3인 경우에 A, A, A를 눌러 A 3개를 출력할 수 있다.

N = 7인 경우에는 A, A, A, Ctrl-A, Ctrl-C, Ctrl-V, Ctrl-V를 눌러 9개를 출력할 수 있다.

N = 11인 경우에는 A, A, A, Ctrl-A, Ctrl-C, Ctrl-V, Ctrl-V, Ctrl-A, Ctrl-C, Ctrl-V, Ctrl-V 를 눌러 27개를 출력할 수 있다.

d[n] 은 n번 눌렀을 때의 최대 출력 개수로 정의

n = 3 까지 인 경우는 d[n] = d[n-1] + 1
n 4인 경우는 두가지 중 최대 값:
AAAA
A(ACV)

n 5인 경우는 3가지 중 최대 값:
AAAAA = d[n-1] + 1 = 5
AA(ACV) = d[n-3] * 2 = 4
A(ACV)V = d[n-4] * 3 = 3

n 7인 경우는 5가지 중 최대 값:
AAAAAAA = d[n-1] + 1 = 5
AAAA(ACV) = d[n-3] * 2 = 8
AAA(ACVV) = d[n-4] * 3 = 9
AA(ACVVV) = d[n-5] * 4 = 8
A(ACVVVV) = d[n-6] * 5 = 5

int를 넘는 것에 주의 해야 한다.

제곱수의 합

제곱수의 합

어떤 자연수 N은 그보다 작은 제곱수들의 합으로 나타낼 수 있다. 예를 들어 11=32+12+12(3개 항)이다. 이런 표현방법은 여러 가지가 될 수 있는데, 11의 경우 11=22+22+12+12+12(5개 항)도 가능하다. 이 경우, 수학자 숌크라테스는 “11은 3개 항의 제곱수 합으로 표현할 수 있다.”라고 말한다. 또한 11은 그보다 적은 항의 제곱수 합으로 표현할 수 없으므로, 11을 그 합으로써 표현할 수 있는 제곱수 항의 최소 개수는 3이다.

주어진 자연수 N을 이렇게 제곱수들의 합으로 표현할 때에 그 항의 최소개수를 구하는 프로그램을 작성하시오.

cache[n] 은 n의 최소 제곱수의 합 정의
52는 어떻게 표현 할 수 있을까?

52같은 경우 큰 수부터 빼 나가면 49 + 1 + 1 + 1 로 4개의 항을 쓴다. 하지만 36 + 16으로 2항으로 가능해 가능한 제곱수를 다 빼 보고 그중 최소값을 택한다 (다 해보는 수밖에 없다?).
[52 - 1]
[52 - 4]
[52 - 9]

[52 - 49]

cache[i] = min(cache[i], cache[i - j*j] + 1)

복잡도: O(N * squrt(N))

cache[1] = 1;
for (i = 2; i <= n; i++) {
    cache[i] = i;
    for (j = 2; j * j <= i; j++) {
        cache[i] = min(cache[i], cache[i - j*j] + 1)
    }
}
삼각화단 만들기

삼각화단 만들기

주어진 화단 둘레의 길이를 이용하여 삼각형 모양의 화단을 만들려고 한다. 이 때 만들어진 삼각형 화단 둘레의 길이는 반드시 주어진 화단 둘레의 길이와 같아야 한다. 또한, 화단 둘레의 길이와 각 변의 길이는 자연수이다.
예를 들어, 만들고자 하는 화단 둘레의 길이가 9m라고 하면
한 변의 길이가 1m, 두 변의 길이가 4m인 화단,
한 변의 길이가 2m, 다른 변의 길이가 3m, 나머지 변의 길이가 4m인 화단,
세 변의 길이가 모두 3m인 3가지 경우의 화단을 만들 수 있다.