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 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

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

 

1253번: 좋다

첫째 줄에는 수의 개수 N(1 ≤ N ≤ 2,000), 두 번째 줄에는 i번째 수를 나타내는 Ai가 N개 주어진다. (|Ai| ≤ 1,000,000,000, Ai는 정수)

www.acmicpc.net

투 포인터를 이용하여 배열 내의 어떤 수를 다른 두개의 합으로 나타낼 수 있는지 확인합니다.

투 포인터 사용을 위해 배열을 오름차순으로 정렬하고, 0번 인덱스부터 N - 1번 인덱스까지 전부 확인합니다.

초기 값은 left = 0, right = N - 1이며, 합이 list[i]와 같으면 바로 break, 합이 더 크면 right를 1 감소, 합이 더 작으면 left를 1 증가시킵니다.

 

이 문제에서 주의할 점은 "수의 위치가 다르면 값이 같아도 다른 수이다" 부분입니다.

자기 자신과 0을 더하는 경우가 나올 수 있는 left 또는 right가 i와 일치한 경우만 제외하였습니다.

 

 

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
#include <iostream>
#include <algorithm>
#define MAX 2000
using namespace std;
 
int list[MAX];
int N;
 
void func() {
    int ans = 0;
    for (int i = 0; i < N; i++) {
        int l = 0;
        int r = N - 1;
        while (l < r) {
            if (l == i) {
                l++;
                continue;
            }
            if (r == i) {
                r--;
                continue;
            }
 
            int sum = list[l] + list[r];
            if (sum == list[i]) {
                ans++;
                break;
            }
            else if (sum > list[i]) {
                r--;
            }
            else {
                l++;
            }
        }
    }
 
    cout << ans << '\n';
}
 
void input() {
    cin >> N;
    for (int i = 0; i < N; i++) {
        cin >> list[i];
    }
    sort(list, list + N);
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

'algorithm > Two-Pointer' 카테고리의 다른 글

boj 9024 두 수의 합  (0) 2021.10.21
boj 17609 회문  (0) 2021.03.29
boj 2559 수열  (0) 2021.02.12
boj 1806 부분합  (0) 2021.01.22
boj 2003 수들의 합 2  (0) 2021.01.22

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

 

9024번: 두 수의 합

프로그램은 표준입력으로 입력을 받는다. 프로그램 입력은 t 개의 테스트 케이스로 구성된다. 입력의 첫 번째 줄에 테스트 케이스의 개수를 나타내는 정수 t 가 주어진다. 두 번째 줄부터 두 줄

www.acmicpc.net

배열에서 합이 K에 가장 가까운 서로 다른 두 개의 정수 조합의 갯수를 구하는 문제입니다.

이 문제는 투 포인터를 이용하여 해결할 수 있습니다.

 

투 포인터 사용을 위해 배열을 오름차순으로 정렬합니다.

그리고 left = 0, right = N - 1에서 시작합니다.

 

두 정수의 합(list[l] + list[r])이 K에 더 가까우면 합(ans)을 갱신, 갯수를 의미하는 cnt를 1로 초기화합니다.

만약 두 정수의 합과 갱신된 합이 같으면 cnt를 1 증가합니다.

그리고 두 정수의 합이 K보다 크면 값을 작게 해야하므로 right를 1 감소,

두 정수의 합이 K보다 작으면 값을 크게 해야하므로 left를 1 증가시킵니다.

 

최종으로 K에 가장 가까운 두 정수의 조합의 갯수인 cnt를 출력합니다.

 

 

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>
#define MAX 1000000
using namespace std;
 
int list[MAX];
int N, K;
 
void func() {
    int l = 0;
    int r = N - 1;
    int ans = 2e8;
    int cnt = 0;
    while (l < r) {
        int sum = list[l] + list[r];
        if (abs(sum - K) < abs(ans - K)) {
            ans = sum;
            cnt = 1;
        }
        else if (abs(sum - K) == abs(ans - K)) {
            cnt++;
        }
 
        if (sum > K) r--;
        else l++;
    }
 
    cout << cnt << '\n';
}
 
void input() {
    cin >> N >> K;
    for (int i = 0; i < N; i++) {
        cin >> list[i];
    }
    sort(list, list + N);
}
 
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 > Two-Pointer' 카테고리의 다른 글

boj 1253 좋다  (0) 2021.10.21
boj 17609 회문  (0) 2021.03.29
boj 2559 수열  (0) 2021.02.12
boj 1806 부분합  (0) 2021.01.22
boj 2003 수들의 합 2  (0) 2021.01.22

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

 

16120번: PPAP

첫 번째 줄에 문자열이 주어진다. 문자열은 대문자 알파벳 P와 A로만 이루어져 있으며, 문자열의 길이는 1 이상 1,000,000 이하이다.

www.acmicpc.net

P는 PPAP 문자열이며, P를 PPAP로 바꾼 문자열 역시 PPAP 문자열입니다.

이 조건과 문자열 주어졌을 때 PPAP 문자열인지 판별하는 문제입니다.

 

우선 문자열의 처음부터 순회를 합니다.

해당 위치의 문자가

'P'이면 cnt를 1 증가합니다.

'A'이면 cnt가 2 이상이고, 다음 문자가 'P'이면 PPAP문자열이므로 PPAP를 P로 변경합니다.

실제 로직으로는 cnt를 1 감소하고, 다음 인덱스가 P인것을 확인했으니 인덱스도 1 증가합니다.

만약 'A'일때 cnt가 2보다 작거나, 마지막 인덱스이거나, 다음 문자가 'P'가 아니면 NP를 출력합니다.

 

순회가 끝났을때 남는 문자열은 P여야하므로 cnt가 1일때만 PPAP를 출력, 아니면 NP를 출력합니다.

 

 

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
#include <iostream>
#include <string>
using namespace std;
 
string str;
int N;
 
void func() {
    int cnt = 0;
    for (int i = 0; i < N; i++) {
        if (str[i] == 'P') cnt++;
        else {
            if (cnt >= 2 && i < N - 1 && str[i + 1== 'P') {
                cnt--;
                i++;
            }
            else {
                cout << "NP\n";
                return;
            }
        }
    }
 
    if (cnt == 1cout << "PPAP\n";
    else cout << "NP\n";
}
 
void input() {
    cin >> str;
    N = str.size();
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

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

boj 2262 토너먼트 만들기  (0) 2021.10.16
boj 13904 과제  (0) 2021.09.30
boj 1826 연료 채우기  (0) 2021.02.22
boj 8980 택배  (0) 2021.02.16
boj 11000 강의실 배정  (0) 2021.02.16

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

 

2262번: 토너먼트 만들기

월드시에서는 매년 n명의 사람들이 모여 월드 크래프트라는 게임의 토너먼트 대회를 치른다. 이 게임은 특성상 실력만이 승패를 좌우하기 때문에, 아무리 실력이 엇비슷한 사람이 시합을 치러

www.acmicpc.net

주어지는 랭킹은 중복이 없으며, 랭킹이 높은 사람 (숫자가 낮은 사람)이 무조건 이깁니다.

문제에서 요구하는 것은 이 토너먼트에서 각 경기에 임하는 선수들의 랭킹의 차이의 합이 최소가 되도록 대진을 구성해야합니다.

 

랭킹이 낮을수록 (숫자가 클수록) 랭킹의 차이의 합이 커지므로 랭킹이 낮은 선수는 빠르게 경기를 하는 것이 이득입니다.

따라서 랭킹이 낮은 선수부터 차례대로 본인의 좌우 선수들 중 랭킹이 낮은 선수와 경기를 하게 만들면 랭킹의 차이의 합이 최소가 됩니다.

 

 

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
#include <iostream>
#include <algorithm>
#define MAX 256
using namespace std;
 
int list[MAX];
int N;
 
void func() {
    int ans = 0;
    for (int i = N; i > 1; i--) {
        int j = 0;
        for (; j <= N; j++) {
            if (i == list[j]) break;
        }
 
        ans += (i - max(list[j - 1], list[j + 1]));
 
        for (; j < N; j++) {
            list[j] = list[j + 1];
        }
        N--;
    }
 
    cout << ans << '\n';
}
 
void input() {
    cin >> N;
    for (int i = 0; i < N; i++) {
        cin >> list[i];
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

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

boj 16120 PPAP  (0) 2021.10.16
boj 13904 과제  (0) 2021.09.30
boj 1826 연료 채우기  (0) 2021.02.22
boj 8980 택배  (0) 2021.02.16
boj 11000 강의실 배정  (0) 2021.02.16

+ Recent posts