본문 바로가기

알고리즘

모스 부호 사전

문제링크: 모스 부호 사전


동적계획법 문제를 풀 때 유형이 있다.

K번째 답을 찾는 것이라면,


1. 완전정복으로 푼다.

2. skip할 수 있는 지 줄여본다. (이항계수 등으로)

3. 문제 자체를 한번에 풀 수 없는 지 생각해본다. 


위와 같은 순서로 해본다. 


K번째 답을 구할 때에는 

N개에서 M개를 뽑는 가짓수를 이용해서 할 수 있는지 생각한다.

nCm = n-1Cm + n-1Cm-1 임을 이용한다!!! 



n: 1, m:0으로 생각.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <string>
using namespace std;
int N = 2, M = 3;
void solve(int n, int m, string s) {
    if (n == 0 && m == 0) {
        cout << s << endl;
        return;
    }
    if(n>0) solve(n - 1, m, s + '0');
    if(m>0) solve(n, m - 1, s + '1');
}
 
void main() {
    string s = "";
    solve(N, M, s);
    return;
}
cs


을 호출 하면, 0 n개, 1 m개를 뽑는 가짓수를 오름차순으로 출력한다. 


solve는 iostream만을 이용해서 recursive로 call하면서 n+mC개를 넘으면 트리의 하위 가짓수를 call하지 않고

뛰어 넘도록 짠 코드이다. 


solve2의 경우는 모든 경우의 수를 돌면서 계산하고 skip하는 solve함수의 방식이 아니라,

각자리를 하나하나 결정하고 넘어가는 방식이다. 

n+mC개에서 K가 m+n-1에서 n-1개를 선택한 것보다 크면, n을 하나 선택했으므로, 1을 선택하고, m-1개만 고르면 되도록 함수를 호출하고,

작으면 그 범위에 있으므로, 0를 선택하고, n-1개 m개를 선택하도록 함수를 호출하면 된다. 


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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <iostream>
#include <string>
using namespace std;
#define min(a,b) (a)<(b) ? (a):(b)
int C, N, M, K;
int index;
char moss[201];
const int MAX = 1000000000;
const char A = 45//-
const char B = 111;     //o
string moss2;
int top = 0;
int bino[1000][1000];
 
void binomial(int num) {
    bino[1][0= bino[1][1= 1;
    for (int i = 2; i < num; i++) {
        bino[i][0= bino[i][i] = 1;
        for (int j = 1; j < i; j++) {
            bino[i][j] = min(MAX, bino[i - 1][j] + bino[i - 1][j - 1]);
        }
    }
}
 
void solve2(int n, int m, string s) {
    if (n == 0) {
        for (int i = 0; i < m; i++)
            s += B;
        cout << s << endl;
        return;
    }else if(m==0) {
        for (int i = 0; i < n; i++)
            s += A;
        cout << s << endl;
        return;
    }
    int skip = bino[m + n - 1][n - 1];
    if (K > skip) {
        K -= skip;
        solve2(n, m - 1, s + B);
    }
    else {
        solve2(n - 1, m, s + A);
    }
 
}
void solve(int n, int m, char *s) {
    if (n == 0 && m == 0) {
        K--;
        if (K == 0) {
            for (int i = 0; i < (M + N); i++) {
                cout << moss[i];
            }
            cout << endl;
        }
 
        return;
    }
 
    int skip = bino[n+m][n];
    if (K > skip) {
        K -= skip;
        return;
    }
    if (K < 0)
        return;
    if (n > 0) {
        moss[top++= A;
        solve(n - 1, m, moss);
        top--;
    }
    if (m > 0) {
        moss[top++= B;
        solve(n, m - 1, moss);
        top--;
    }
 
}
 
int main() {
    freopen("input.txt""r", stdin);
 
    cin >> C;
    binomial(200);
 
    for (int c = 0; c < C; c++) {
        cin >> N >> M >> K;
        top = 0;
        index = 0;
        //solve(N, M, moss);
        solve2(N, M, moss2);
    }
    return 0;
}
cs