https://www.acmicpc.net/problem/14725

 

14725번: 개미굴

첫 번째 줄은 로봇 개미가 각 층을 따라 내려오면서 알게 된 먹이의 정보 개수 N개가 주어진다.  (1 ≤ N ≤ 1000) 두 번째 줄부터 N+1 번째 줄까지, 각 줄의 시작은 로봇 개미 한마리가 보내준 먹이

www.acmicpc.net

개미굴의 각 저장소들을 트라이 방식으로 저장할 수 있습니다.

A B C 이런식으로 입력이 들어오면 A 다음 B 다음 C 이런식으로 저장하는 방식입니다.

 

다만 들어오는 데이터가 문자열 방식이므로 일반적인 배열로는 할 수 없으며 map를 사용합니다.

m.find(str) 메소드를 이용하여 해당 depth에 문자열이 저장되었는지 확인 후

저장되었다면 다음 depth로 이동, 저장되지 않았다면 해당 depth의 map에 문자열을 저장 후 다음 depth로 이동합니다.

 

출력은 개미굴의 구조를 사전 순으로 출력합니다.

map은 이미 정렬이 된 자료구조이므로 iterator를 이용하여 사전 순으로 출력해줍니다.

 

 

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
#include <iostream>
#include <map>
#include <string>
#define MAX 16
using namespace std;
 
string list[MAX];
int N, M;
 
typedef struct Trie {
    map<string, Trie*> m;
 
    ~Trie() {
        map<string, Trie*>::iterator iter = m.begin();
        for (; iter != m.end(); iter++) {
            delete (*iter).second;
        }
    }
 
    void insert(int idx) {
        if (idx == M) return;
 
        if (m.find(list[idx]) == m.end()) {
            m.insert({ list[idx], new Trie() });
            m[list[idx]]->insert(idx + 1);
        }
        else {
            m[list[idx]]->insert(idx + 1);
        }
    }
 
    void find(int depth) {
        map<string, Trie*>::iterator iter = m.begin();
        for (; iter != m.end(); iter++) {
            for (int i = 0; i < depth; i++) {
                cout << "--";
            }
            cout << (*iter).first << '\n';
 
            (*iter).second->find(depth + 1);
        }
    }
}Trie;
 
Trie *t;
 
void func() {
    t->find(0);
}
 
void init() {
    t = new Trie();
}
 
void input() {
    init();
    cin >> N;
    for (int i = 0; i < N; i++) {
        cin >> M;
        for (int j = 0; j < M; j++) {
            cin >> list[j];
        }
        t->insert(0);
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

'algorithm > Trie' 카테고리의 다른 글

boj 5052 전화번호 목록  (0) 2022.03.27

https://www.acmicpc.net/problem/5052

 

5052번: 전화번호 목록

첫째 줄에 테스트 케이스의 개수 t가 주어진다. (1 ≤ t ≤ 50) 각 테스트 케이스의 첫째 줄에는 전화번호의 수 n이 주어진다. (1 ≤ n ≤ 10000) 다음 n개의 줄에는 목록에 포함되어 있는 전화번호가

www.acmicpc.net

트라이를 연습하려고 풀었던 문제입니다.

 

트라이에 주어지는 전화번호들을 전부 넣은 다음, 넣었던 전화번호들을 트라이 안에서 검색합니다.

검색하던 도중 해당 전화번호까지 가기 전에 isEnd를 만나면 접두어가 있다는 뜻이므로 NO를 출력합니다.

모든 전화번호를 탐색하여 접두어를 만나지 못하면 YES를 출력합니다.

 

 

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
#include <iostream>
#include <string>
#include <algorithm>
#include <cstring>
#define MAX 10001
using namespace std;
 
char list[MAX][11];
int N;
 
int charToInt(char x) {
    return x - '0';
}
 
typedef struct Trie {
    bool isEnd;
    Trie *next[10];
    Trie() : isEnd(false) {
        memset(next, 0sizeof(next));
    }
 
    ~Trie() {
        for (int i = 0; i < 10; i++) {
            if (next[i]) delete next[i];
        }
    }
 
    void insert(char *key) {
        if (*key == '\0') {
            isEnd = true;
        }
        else {
            int idx = charToInt(*key);
            if (!next[idx]) next[idx] = new Trie();
            next[idx]->insert(key + 1);
        }
    }
 
    bool find(char *key) {
        if (*key == '\0'return true;
        if (isEnd) return false;
 
        int idx = charToInt(*key);
        return next[idx]->find(key + 1);
    }
}Trie;
 
Trie *t;
 
void func() {
    for (int i = 0; i < N; i++) {
        if (!(t->find(list[i]))) {
            cout << "NO\n";
            return;
        }
    }
 
    cout << "YES\n";
}
 
void input() {
    t = new Trie();
    cin >> N;
    for (int i = 0; i < N; i++) {
        cin >> list[i];
        t->insert(list[i]);
    }
}
 
void init() {
    delete t;
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    int tc;
    cin >> tc;
    while (tc--) {
        input();
        func();
        init();
    }
 
    return 0;
}
cs

'algorithm > Trie' 카테고리의 다른 글

boj 14725 개미굴  (0) 2022.03.27

https://www.acmicpc.net/problem/10986

 

10986번: 나머지 합

수 N개 A1, A2, ..., AN이 주어진다. 이때, 연속된 부분 구간의 합이 M으로 나누어 떨어지는 구간의 개수를 구하는 프로그램을 작성하시오. 즉, Ai + ... + Aj (i ≤ j) 의 합이 M으로 나누어 떨어지는 (i, j)

www.acmicpc.net

[boj 3673 나눌 수 있는 부분 수열] 문제와 같은 풀이 방법입니다.

 

모든 수열의 누적합을 구해 각각의 누적 합의 %M 값을 사용합니다.

1
2
5 3
1 2 3 1 2
cs

위의 입력을 예시로 들면

1
2
sum   = 1 3 6 7 9
MOD M = 1 0 0 1 0
cs

이렇게 됩니다. 저는 이번 문제는 dp에 MOD M한 값을 미리 저장해두었고, cnt[dp[i]]으로 카운팅 하였습니다.

 

M = 3이므로

나머지가 0인 갯수는 3

나머지가 1인 갯수는 2이므로

 

나머지가 같은 부분 수열에서 2개를 뽑는 조합을 더하는 식으로 구할 수 있습니다.

 

 

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
#include <iostream>
#define MAX_N 1000001
#define MAX_M 1001
using namespace std;
typedef long long ll;
 
ll cnt[MAX_M], ans;
int dp[MAX_N];
int N, M;
 
void func() {
    ans = cnt[0];
    for (int i = 0; i < M; i++) {
        ans += (cnt[i] * (cnt[i] - 1/ 2LL);
    }
 
    cout << ans << '\n';
}
 
void input() {
    cin >> N >> M;
    for (int i = 1; i <= N; i++) {
        cin >> dp[i];
 
        dp[i] = (dp[i] + dp[i - 1]) % M;
        cnt[dp[i]]++;
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

'algorithm > dp' 카테고리의 다른 글

boj 21923 곡예 비행  (0) 2022.06.10
boj 12978 스크루지 민호 2  (0) 2022.06.08
boj 14238 출근 기록  (0) 2022.02.04
boj 3673 나눌 수 있는 부분 수열  (0) 2022.01.31
boj 20500 Ezreal 여눈부터 가네 ㅈㅈ  (0) 2022.01.01

https://www.acmicpc.net/problem/21939

 

21939번: 문제 추천 시스템 Version 1

tony9402는 최근 깃헙에 코딩테스트 대비 문제를 직접 뽑아서 "문제 번호, 난이도"로 정리해놨다. 깃헙을 이용하여 공부하시는 분들을 위해 새로운 기능을 추가해보려고 한다. 만들려고 하는 명령

www.acmicpc.net

recommend x

x가 1인 경우 리스트에서 가장 어려운 문제의 번호를 출력, 가장 어려운 문제가 여러 개면 문제 번호가 큰 것을 출력

x가 -1인 경우 리스트에서 가장 쉬운 문제의 번호를 출력, 가장 어려운 문제가 여러 개면 문제 번호가 작은 것을 출력

 

add P L

리스트에 난이도가 L인 문제 번호 P를 추가한다.

현재 리스트에 없는 문제만 들어오며, 이미 해결하여 리스트에서 제외된 문제가 다시 들어올 수 있다.

 

solved P

리스트에서 문제 번호 P를 제거한다. (해결한 것으로 간주)

 

문제들은 [문제 번호, 난이도] 로 정리되어 있으며, 들어온 순서대로 명령을 처리하는 문제입니다.

recommend 명령어에서 난이도가 가장 어려운 문제와 가장 쉬운 문제를 빠르게 뽑아내야 하므로 우선 순위 큐를 2개 사용하며, 최대 우선순위 큐와 최소 우선순위 큐를 같이 관리합니다.

 

각 문제의 난이도를 나타내기 위해 levellist라는 배열을 사용하였으며, 값이 0이 아니라면 리스트에 있는 문제라는 뜻입니다.

이를 이용하여 solved 시 levellist의 값을 0으로 바꾸고, recommend 명령어가 들어왔을 때 출력하기 전에 현재 최대/최소 우선순위 큐에 이미 solved된 문제가 있는지 확인하는 작업을 거친 후에 출력하도록 합니다.

 

 

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
#include <iostream>
#include <queue>
#include <algorithm>
#include <set>
#include <string>
#define MAX 100001
using namespace std;
typedef pair<intint> pi;
 
priority_queue<pi, vector<pi>, less<pi> > mxq;
priority_queue<pi, vector<pi>, greater<pi> > mnq;
int levellist[MAX];
int N, M;
 
void func() {
    string type;
    int x, y;
    cin >> M;
    while (M--) {
        cin >> type;
        if (type == "add") {
            cin >> x >> y;
            mxq.push({ y,x });
            mnq.push({ y,x });
            levellist[x] = y;
        }
        else {
            cin >> x;
            if (type == "recommend") {
                if (x == 1) {
                    while (1) {
                        int p = mxq.top().second;
                        int l = mxq.top().first;
                        if (levellist[p] == l) break;
                        mxq.pop();
                    }
 
                    cout << mxq.top().second << '\n';
                }
                else {
                    while (1) {
                        int p = mnq.top().second;
                        int l = mnq.top().first;
                        if (levellist[p] == l) break;
                        mnq.pop();
                    }
 
                    cout << mnq.top().second << '\n';
                }
            }
            else {
                levellist[x] = 0;
            }
        }
    }
}
 
void input() {
    int P, L;
    cin >> N;
    for (int i = 0; i < N; i++) {
        cin >> P >> L;
        mxq.push({ L,P });
        mnq.push({ L,P });
        levellist[P] = L;
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
    
    return 0;
}
cs

'algorithm > data-structure' 카테고리의 다른 글

boj 29721 변형 체스 놀이 : 다바바(Dabbaba)  (2) 2025.02.14
boj 15926 현욱은 괄호왕이야!!  (1) 2023.07.24
boj 17299 오등큰수  (0) 2021.02.22
boj 9372 상근이의 여행  (0) 2021.02.09
boj 1158 요세푸스 문제  (0) 2021.02.09

https://www.acmicpc.net/problem/14238

 

14238번: 출근 기록

스타트링크에는 세명의 직원이 일을 하고 있다. 세 직원의 이름은 강호(A), 준규(B), 수빈(C) 이다. 이 회사의 직원은 특별한 룰을 가지고 있는데, 바로 하루에 한 명만 출근한다는 것이다. 3일간의

www.acmicpc.net

 

dp[a][b][c][pre1][pre2]: 현재까지 A, B, C가 각각 a, b, c번 출근하였고, 전날 출근을 pre1, 전전날 출근을 pre2가 했을 때 올바른 출근 기록인지 여부

 

1일마다 A, B, C 중 한 명이 무조건 출근하며

A: 매일 출근할 수 있다.

B: 출근한 다음날은 반드시 쉬어야 한다.

C: 출근한 다음날과 다다음날은 반드시 쉬어야 한다.

위 조건들을 이용해서 구현 해야 합니다.

 

리턴 받은 값이 1이면 올바른 출근기록이므로 순서대로 출력해주시면 됩니다.

0을 리턴받았으면 올바른 출근기록이 없으니 -1을 출력합니다.

 

 

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
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#define MAX 51
using namespace std;
 
string str;
int dp[MAX][MAX][MAX][3][3];
int cnt[3];
int N;
 
int dfs(int a, int b, int c, int pre1, int pre2) {
    if (a + b + c == N) return 1;
    int &ret = dp[a][b][c][pre1][pre2];
    if (ret != -1return ret;
    ret = 0;
 
    if (a < cnt[0]) {
        ret = dfs(a + 1, b, c, 0, pre1);
        if (ret == 1) {
            cout << 'A';
            return ret;
        }
    }
 
    if (b < cnt[1]) {
        if (pre1 != 1) {
            ret = dfs(a, b + 1, c, 1, pre1);
            if (ret == 1) {
                cout << 'B';
                return ret;
            }
        }
    }
 
    if (c < cnt[2]) {
        if (pre1 != 2 && pre2 != 2) {
            ret = dfs(a, b, c + 12, pre1);
            if (ret == 1) {
                cout << 'C';
                return ret;
            }
        }
    }
 
    return ret;
}
 
void func() {
    memset(dp, -1sizeof(dp));
    if (!dfs(00000)) cout << "-1\n";
}
 
void init() {
    N = str.size();
    for (int i = 0; i < N; i++) {
        cnt[str[i] - 'A']++;
    }
}
 
void input() {
    cin >> str;
    init();
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

'algorithm > dp' 카테고리의 다른 글

boj 12978 스크루지 민호 2  (0) 2022.06.08
boj 10986 나머지 합  (0) 2022.03.08
boj 3673 나눌 수 있는 부분 수열  (0) 2022.01.31
boj 20500 Ezreal 여눈부터 가네 ㅈㅈ  (0) 2022.01.01
boj 1135 뉴스 전하기  (0) 2021.11.15

https://www.acmicpc.net/problem/3673

 

3673번: 나눌 수 있는 부분 수열

양의 정수로 이루어진 수열이 주어졌을 때, 연속하는 부분 수열의 합이 d로 나누어 떨어지는 것의 개수를 구하는 프로그램을 작성하시오. 예를 들어, 아래와 같은 수열의 부분 수열 중 4로 나누

www.acmicpc.net

M으로 나누어 떨어지는 연속하는 부분 수열의 합의 갯수를 찾는 문제입니다.

이 문제의 키워드는 "연속" 이며, 누적 합을 이용합니다.

 

1
2
M = 4, N = 8
2 1 2 1 1 2 1 2
cs

위의 입력을 예시로 우선 수열의 누적합을 구해 각각의 MOD M을 구합니다.

 

1
2
sum   = 2 3 5 6 7 9 10 12
MOD M = 2 3 1 2 3 1 2 0
cs

그러면 위와 같이 누적 합과 누적 합의 MOD M 값을 카운팅합니다.

 

M = 4이므로

나머지가 0인 갯수는 1

나머지가 1인 갯수는 2

나머지가 2인 갯수는 3

나머지가 3인 갯수는 2

이렇게 됩니다.

 

여기서 나머지가 1인 부분 수열을 설명하면

sum(1 ~ 3), sum(1 ~ 6)의 나머지가 1로 같다는 말입니다.

그러면 sum(4 ~ 6)의 나머지는 0이라는 말이 됩니다.

따라서 나머지가 같은 부분 수열에서 2개를 뽑는 조합을 구하면 되는 겁니다.

 

나머지가 1인 부분 수열은 2개이므로 2개 중에 2개를 뽑는 경우의 수: 1

 

나머지가 2인 부분 수열은

sum(1 ~ 1), sum(1 ~ 4), sum(1 ~ 7)로 3개로

3개 중에 2개를 뽑는 경우의 수로 3이라는 답이 나옵니다.

 

같은 방식으로 나머지가 0 ~ M - 1일 때의 경우의 수를 모두 구해줍니다.

 

 

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
#include <iostream>
#include <cstring>
#define MAX_N 50001
#define MAX_M 1000000
using namespace std;
typedef long long ll;
 
ll dp[MAX_N], cnt[MAX_M];
int N, M;
 
void func() {
    ll ans = cnt[0];
    for (int i = 0; i < M; i++) {
        if (cnt[i] < 2continue;
        ans += ((cnt[i] * (cnt[i] - 1)) / 2LL);
    }
 
    cout << ans << '\n';
}
 
void input() {
    cin >> M >> N;
    for (int i = 1; i <= N; i++) {
        cin >> dp[i];
        dp[i] += dp[i - 1];
 
        cnt[dp[i] % M]++;
    }
}
 
void init() {
    memset(cnt, 0sizeof(cnt));
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    int tc;
    cin >> tc;
    while (tc--) {
        input();
        func();
        init();
    }
 
    return 0;
}
cs

'algorithm > dp' 카테고리의 다른 글

boj 10986 나머지 합  (0) 2022.03.08
boj 14238 출근 기록  (0) 2022.02.04
boj 20500 Ezreal 여눈부터 가네 ㅈㅈ  (0) 2022.01.01
boj 1135 뉴스 전하기  (0) 2021.11.15
boj 17090 미로 탈출하기  (0) 2021.06.27

https://www.acmicpc.net/problem/20500

 

20500번: Ezreal 여눈부터 가네 ㅈㅈ

문제의 답을 $1\,000\,000\,007$로 나눈 나머지를 출력한다.

www.acmicpc.net

1과 5로만 이루어진 N자리 양의 정수 중에서 15의 배수가 몇 개인지 구하는 문제입니다.

 

15의 배수는 3의 배수 * 5의 배수입니다.

따라서 3의 배수이고, 5의 배수인 것을 찾으면 됩니다.

 

dp[N][R]: N자리의 양의 정수를 3으로 나눈 나머지가 R인 경우의 수

따라서 먼저 5의 배수를 만들어 놓고, 3으로 나눈 나머지를 확인하도록 합니다.

 

우선 N = 1일때는 15의 배수가 없으므로 패스합니다.

N = 2일때는 5의 배수가 15, 55가 있습니다.

15는 3으로 나눈 나머지가 0이므로 dp[2][0]에 해당하고,

55는 3으로 나눈 나머지가 1이므로 dp[2][1]에 해당합니다.

따라서 초기 값은 dp[2][0] = 1, dp[2][1] = 1입니다.

 

그 다음 N = 3일때는 N = 2일 경우에 1 또는 5를 붙인 경우를 더해주시면 됩니다.

dp[3][0]은 dp[2][1]에서 앞자리에 5를 더한 경우 + dp[2][2]에서 앞자리에 1을 더한 경우

dp[3][1]은 dp[2][0]에서 앞자리에 1을 더한 경우 + dp[2][2]에서 앞자리에 5를 더한 경우

dp[3][2]는 dp[2][0]에서 앞자리에 5를 더한 경우 + dp[2][1]에서 앞자리에 1을 더한 경우

 

따라서 점화식은 위와같이

dp[i][0] = dp[i - 1][1] + dp[i - 1][2]

dp[i][1] = dp[i - 1][0] + dp[i - 1][2]

dp[i][2] = dp[i - 1][0] + dp[i - 1][1]

이렇게 됩니다.

 

결과로는 MOD를 한 값을 출력해야 하므로 더하면서 MOD값을 넣어주도록 합니다.

 

 

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
#include <iostream>
#define MAX 1516
#define MOD 1000000007
using namespace std;
 
int dp[MAX][3];
int N;
 
void init() {
    dp[2][0= 1;
    dp[2][1= 1;
    for (int i = 3; i < MAX; i++) {
        dp[i][0= (dp[i - 1][1+ dp[i - 1][2]) % MOD;
        dp[i][1= (dp[i - 1][0+ dp[i - 1][2]) % MOD;
        dp[i][2= (dp[i - 1][0+ dp[i - 1][1]) % MOD;
    }
}
 
void input() {
    cin >> N;
    cout << dp[N][0<< '\n';
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    init();
    input();
 
    return 0;
}
cs

'algorithm > dp' 카테고리의 다른 글

boj 14238 출근 기록  (0) 2022.02.04
boj 3673 나눌 수 있는 부분 수열  (0) 2022.01.31
boj 1135 뉴스 전하기  (0) 2021.11.15
boj 17090 미로 탈출하기  (0) 2021.06.27
boj 1648 격자판 채우기  (0) 2021.06.22

https://www.acmicpc.net/problem/9081

 

9081번: 단어 맞추기

입력의 첫 줄에는 테스트 케이스의 개수 T (1 ≤ T ≤ 10)가 주어진다. 각 테스트 케이스는 하나의 단어가 한 줄로 주어진다. 단어는 알파벳 A~Z 대문자로만 이루어지며 항상 공백이 없는 연속된 알

www.acmicpc.net

문자열이지만 순열에 더 가까운 문제입니다.

주어진 단어의 사전 순으로 바로 다음 단어를 출력하는 문제로, next_permutation을 이용하였습니다.

next_permutation으로 다음 순열을 구하고, 출력하면 됩니다.

만약 마지막 단어라서 다음 순열을 구하지 못하더라도 주어진 단어를 유지하므로 그냥 출력해줍니다.

c++ 내장의 next_permutation을 사용하면 됐지만 직접 구현해보았습니다.

 

 

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
#include <iostream>
#include <string>
using namespace std;
 
string str;
int N;
 
bool nextPermutation() {
    int i = N - 1;
 
    while (i > 0 && str[i - 1>= str[i]) {
        i--;
    }
 
    if (!i) return false;
 
    int j = N - 1;
    while (str[i - 1>= str[j]) j--;
 
    swap(str[i - 1], str[j]);
 
    int k = N - 1;
    while (i < k) swap(str[i++], str[k--]);
 
    return true;
}
 
void func() {
    nextPermutation();
 
    cout << str << '\n';
}
 
void input() {
    cin >> str;
    N = str.size();
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    int tc;
    cin >> tc;
    while (tc--) {
        input();
        func();
    }
 
    return 0;
}
cs

'algorithm > String' 카테고리의 다른 글

boj 10453 문자열 변환  (0) 2024.07.24
boj 10096 세 친구  (0) 2021.01.29

https://www.acmicpc.net/problem/23059

 

23059번: 리그 오브 레게노

첫째 줄에는 백남이가 알고 있는 아이템 사이의 관계의 수 $N$(1 ≤ $N$ ≤ 200,000)를 입력받는다. $N$개의 줄에 걸쳐서 아이템 이름을 의미하는 문자열 2개 A B가 주어진다. 아이템 A는 아이템 B를 구

www.acmicpc.net

간만에 위상정렬 문제입니다.

이 문제는 문자열을 인덱스로 변환해야 하지만 출력하는게 문자열이라 문자열 기준, 인덱스 기준의 맵을 따로 사용하였습니다.

intToString에는 인덱스 기준 문자열, stringToInt에는 문자열 기준 인덱스를 저장합니다.

이 부분이 해당 문자열에 대한 인덱스 값을 구해 맵에 넣는 과정입니다.

stringToInt와 intToString에 같이 넣어줍니다.

그 다음 위상정렬로 구매할 아이템의 순서를 정해주면 되는데

여기서 현재 같은 우선순위의 아이템은 사전 순으로 구매하기 때문에 우선순위를 인덱스로 둔 배열을 사용하였습니다.

우선순위가 낮은 (인덱스가 낮은) 배열부터 문자열들을 사전 순으로 정렬한 후에 출력합니다.

 

이 문제에서 N이 200000이라 MAX를 200000으로 잡았는데.. N이 문자열 갯수가 아닌 관계의 수였습니다..

이런 실수를 좀 줄여야겠습니다..

 

그리고 처음에는 map을 사용했었는데 시간 초과가 발생해서 unordered_map으로 바꾸니 AC를 받았습니다.

찾아보니 데이터가 많을 때 unordered_map의 성능이 훨씬 좋다고 하는 것을 보았습니다.

하지만 이 둘의 차이를 공부할 필요가 있어보입니다.

 

 

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
95
96
#include <iostream>
#include <unordered_map>
#include <queue>
#include <string>
#include <vector>
#include <algorithm>
#define MAX 400000
using namespace std;
typedef pair<intint> pi;
 
unordered_map<intstring> intToString;
unordered_map<stringint> stringToInt;
vector<int> graph[MAX], ans[MAX];
int conn[MAX];
int N, idx;
 
bool cmp(int a, int b) {
    return intToString[a] < intToString[b];
}
 
void print() {
    for (int i = 0; ; i++) {
        if (!ans[i].size()) return;
 
        sort(ans[i].begin(), ans[i].end(), cmp);
        for (int j = 0; j < ans[i].size(); j++) {
            cout << intToString[ans[i][j]] << '\n';
        }
    }
}
 
void func() {
    queue<pi> q;
    for (int i = 0; i < idx; i++) {
        if (!conn[i]) {
            q.push({ i,0 });
            ans[0].push_back(i);
        }
    }
 
    for (int t = 0; t < idx; t++) {
        if (q.empty()) {
            cout << "-1\n";
            return;
        }
 
        int x = q.front().first;
        int cnt = q.front().second;
        q.pop();
 
        for (int i = 0; i < graph[x].size(); i++) {
            int next = graph[x][i];
 
            conn[next]--;
 
            if (!conn[next]) {
                q.push({ next, cnt + 1 });
                ans[cnt + 1].push_back(next);
            }
        }
    }
 
    print();
}
 
void input() {
    string str1, str2;
    cin >> N;
    for (int i = 0; i < N; i++) {
        cin >> str1 >> str2;
 
        if (stringToInt.find(str1) == stringToInt.end()) {
            stringToInt.insert({ str1, idx });
            intToString.insert({ idx++, str1 });
        }
        if (stringToInt.find(str2) == stringToInt.end()) {
            stringToInt.insert({ str2, idx });
            intToString.insert({ idx++, str2 });
        }
 
        int a = stringToInt[str1];
        int b = stringToInt[str2];
        graph[a].push_back(b);
        conn[b]++;
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

'algorithm > Topological-sort' 카테고리의 다른 글

boj 2252 줄 세우기  (0) 2021.02.07

https://www.acmicpc.net/problem/17244

 

17244번: 아맞다우산

경재씨는 저녁 약속을 가기 전 챙기지 않은 물건들이 있는 지 확인하고 있다. 필요한 물건은 전부 챙긴 것 같았고 외출 후 돌아오는 길에 경재씨는 외쳤다. "아 맞다 우산!!!" 경재 씨는 매번 외출

www.acmicpc.net

챙겨야 하는 물건은 최대 5개이므로 bfs + 비트마스킹이 가능합니다.

visit[x][y][bit]: 좌표 (x, y)에 도착했을 때 찾은 물건의 비트가 bit인 경우의 방문 처리입니다.

비트를 어떻게 할지 고민하다가 chk배열을 사용하여 해당 좌표에 있는 물건의 비트를 정해주었습니다.

나가는 문에 도착했을 때 모든 물건을 찾았을 때만 t를 출력합니다.

 

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
#include <iostream>
#include <queue>
#define MAX 50
using namespace std;
typedef pair<pair<intint>int> pii;
 
queue<pii> q;
char list[MAX][MAX];
bool visit[MAX][MAX][1 << 5];
int chk[MAX][MAX];
int direct[4][2= { {0,1},{1,0},{0,-1},{-1,0} };
int N, M, bit;
 
void bfs() {
    for (int t = 1!q.empty(); t++) {
        int qsize = q.size();
        while (qsize--) {
            int x = q.front().first.first;
            int y = q.front().first.second;
            int cnt = q.front().second;
            q.pop();
 
            for (int i = 0; i < 4; i++) {
                int nx = x + direct[i][0];
                int ny = y + direct[i][1];
                int ncnt = cnt;
 
                if (nx < 0 || ny < 0 || nx >= N || ny >= M) continue;
                if (list[nx][ny] == 'X') {
                    int b = chk[nx][ny];
 
                    ncnt |= b;
                }
                if (list[nx][ny] == '#' || visit[nx][ny][ncnt]) continue;
 
                if (list[nx][ny] == 'E' && ncnt == bit) {
                    cout << t << '\n';
                    return;
                }
 
                q.push({ {nx,ny}, ncnt });
                visit[nx][ny][ncnt] = true;
            }
        }
    }
}
 
void input() {
    int cnt = 0;
    cin >> M >> N;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cin >> list[i][j];
            if (list[i][j] == 'S') {
                q.push({ {i,j},0 });
                visit[i][j][0= true;
            }
            else if (list[i][j] == 'X') {
                chk[i][j] = (1 << cnt);
                cnt++;
            }
        }
    }
 
    bit = (1 << cnt) - 1;
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    bfs();
 
    return 0;
}
cs

'algorithm > bfs' 카테고리의 다른 글

boj 5547 일루미네이션  (0) 2022.05.15
boj 16932 모양 만들기  (0) 2022.05.14
boj 1194 달이 차오른다, 가자.  (0) 2021.04.21
boj 17471 게리맨더링  (0) 2021.04.16
boj 2573 빙산  (0) 2021.04.05

https://www.acmicpc.net/problem/13701

 

13701번: 중복 제거

문제: N개의 정수 A1, A2, ..., AN 을 읽고, 이들 중에서 반복되는 수를 제외하고 남은 N'개의 수 B1, B2, ..., BN’ 을 입력된 순서대로 출력하시오. 이때, 0 ≤ Ai < 225 = 33554432, i=1,2,…,N. 입력의 개수 N은 1

www.acmicpc.net

이 문제는 메모리 제한이 8MB 이므로 2^25만큼의 배열을 사용하면 메모리 초과가 뜹니다.

따라서 이를 수를 구분할 수 있는 몫과 나머지를 이용한 비트마스킹을 이용합니다.

 

인덱스는 몫이 되겠으며, 비트로 사용할 값은 나머지입니다.

x라는 몫에 y라는 나머지가 있는지 비트 연산자로 확인합니다.

y라는 나머지가 있으면 출력, 없으면 return을 시키면 됩니다.

 

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
#include <iostream>
#define MAX 1 + (1 << 20)
using namespace std;
 
int list[MAX];
 
void func(int N) {
    int x = N >> 5;
    int y = N % 32;
    int z = (1 << y);
 
    if (list[x] & z) return;
    list[x] |= z;
    cout << N << ' ';
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    int N;
    while (cin >> N) {
        func(N);
    }
 
    return 0;
}
cs

 

https://www.acmicpc.net/problem/1135

 

1135번: 뉴스 전하기

민식이는 회사의 매니저이다. 그리고, 민식이는 회사의 중요한 뉴스를 모든 직원에게 빠르게 전달하려고 한다. 민식이의 회사는 트리 구조이다. 모든 직원은 정확하게 한 명의 직속 상사가 있다

www.acmicpc.net

 

TreeDP는 난이도도 생각보다 높고, 많이 못 풀어봤어서 그런지 어렵네요..

 

0번 직원부터 시작해서 모든 직원에게 뉴스를 전하는데 최소 시간을 구하는 문제입니다.

한 번에 한 명에게만 전파가 가능하므로 전파하는 시간이 가장 오래걸리는 직속 부하에게 먼저 전파를 해야합니다.

 

list라는 벡터에 자신의 직속 부하에게 전파하는 시간을 모두 저장한 후에 내림차순으로 정렬합니다.

먼저 전파하는 부하에게는 추가적인 시간이 필요하지 않으므로 +0,

두 번째 전파하는 부하에게는 추가적인 시간이 +1,

마지막에 전파하는 부하에게는 list.size() - 1 만큼 추가적인 시간이 추가됩니다.

이 경우들의 최댓값이 자신의 부하직원에게 소식을 전하는데 걸리는 최소 시간입니다.

 

24번째 줄 +1을 한 이유는 부하가 없는 직원에게서 오는 값은 0이기 때문에 1을 더한 것입니다.

 

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
#include <iostream>
#include <algorithm>
#include <vector>
#define MAX 50
using namespace std;
 
vector<int> graph[MAX];
int N;
 
int dfs(int v) {
    vector<int> list;
    int ret = 0;
 
    for (int i = 0; i < graph[v].size(); i++) {
        int next = graph[v][i];
 
        list.push_back(dfs(next));
    }
    sort(list.begin(), list.end(), [](int a, int b) {
        return a > b;
    });
 
    for (int i = 0; i < list.size(); i++) {
        ret = max(ret, list[i] + i + 1);
    }
 
    return ret;
}
 
void func() {
    cout << dfs(0<< '\n';
}
 
void input() {
    int x;
    cin >> N >> x;
    for (int i = 1; i < N; i++) {
        cin >> x;
        graph[x].push_back(i);
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

'algorithm > dp' 카테고리의 다른 글

boj 3673 나눌 수 있는 부분 수열  (0) 2022.01.31
boj 20500 Ezreal 여눈부터 가네 ㅈㅈ  (0) 2022.01.01
boj 17090 미로 탈출하기  (0) 2021.06.27
boj 1648 격자판 채우기  (0) 2021.06.22
boj 14700 넴모넴모 (Hard)  (0) 2021.06.22

+ Recent posts