swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV15Khn6AN0CFAYD&categoryId=AV15Khn6AN0CFAYD&categoryType=CODE&&&

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

<풀이>

1. 교환 횟수가 될 때 까지, 각 자리 숫자를 모두 교환해본다.

2. 교환된 최댓값을 갱신하고, 출력한다.

 

<해법>

1.  교환횟수가 많아질 경우, 시간초과 해결 방법

=> 백트래킹을 이용하여 숫자를 모두 교환하는 방식까지는 쉽게 생각할 수 있습니다. 하지만, 교환횟수가 많아지면 시간초과가 나옵니다. 여기서, 다른 방식으로 문제에 접근해야 겠다는 생각을 할 수 있습니다.

 

샘플 input인 456789, 10 으로 알아보겠습니다.

정답은 987645 입니다. 뒤 두 숫자가 45입니다.

이 말은 많은 반복을 하였음에도 불구하고, 최댓값이 아닐 수 있다 를 의미합니다. 그리고, 987654에서 교환 횟수를 맞추기 위해 987645로 교환을 했다는 것으로 생각할 수 있습니다.

만약 11번 교환할 경우 987654가 되고, 12번 교환할 경우 987645, 13번 987654 ... 이런 식으로 계속 나아갈 것이라고 유추할 수 있습니다.

 

그렇다면 여기서 중요한 것은 '최댓값을 만드는 동전의 최소교환횟수' 라고 생각할 수 있습니다.

그 횟수를 넘어설 경우, 뒤에 두 숫자만 바꾸어서 교환을 진행할 것이기 때문입니다.

 

다시, 위 샘플 input을 풀어보도록 하겠습니다.

456789는 3번의 교환만에 987654(최댓값)을 만들 수 있습니다. 

이후 4번 교환시 987645, 5번 987654, 6번 987645 ... 이렇게 진행됩니다.

 

다른 예시로 풀어보겠습니다. 12345 5 입니다.

12345는 2번의 교환만에 54321을 만들 수 있습니다.

이후 3번 54312, 4번 54321, 5번 54312 이므로 정답은 54312 입니다.

 

규칙이 보이실 거라고 생각합니다.


저의 풀이 방식이었습니다. 더 길게 쓰면 어차피 안보실 것 같아서 쓰지 않았습니다.

위 문제는 테스트 케이스가 몇 개 없어서 정확한 정답이 아닌데도 정답을 맞을 수 있습니다. 

예제 테스트 케이스를 몇개 만들어 보았습니다.

 

//input

14

49 1

49 2

49 3

12345 1

12345 2

12345 3

12345 4

12345 5

456789 1

456789 2

456789 3

456789 4

456789 5

456789 6

 

//output

#1 94
#2 49
#3 94
#4 52341
#5 54321
#6 54312
#7 54321
#8 54312
#9 956784
#10 986754
#11 987654
#12 987645
#13 987654
#14 987645

 

input을 반대로 해보셔도 도움이 될 것 같습니다.(49 -> 94, 12345 -> 54321)

 

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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include <iostream>
#include <string>
#include <algorithm>
 
using namespace std;
 
string s;
int change;
 
//최대 s
string maxS;
 
//maxS를 만들 수 있는 최소교환횟수
int minChangeCnt;
 
//바뀐 change 값
int changeCnt;
 
//정답값
string answer;
 
//문자열 바꾸기
void swap(string& str, int x, int y) {
    char tmp = str[x];
    str[x] = str[y];
    str[y] = tmp;
}
 
//완전탐색(각 자리에서 다른 자리와 교환 or 교환X)
void go(int index, int cnt) {
 
    //모든 자리마다 탐색이 끝난 경우 : 종료
    if (index > s.length()) {
        return;
    }
 
    //maxS를 찾아 낼 경우 : 교환 최소 횟수 갱신
    if (s == maxS) {
        if (minChangeCnt == -1 || cnt < minChangeCnt) {
            minChangeCnt = cnt;
        }
    }
 
    //교환 횟수를 채운 경우 : 최대값 갱신 후 종료
    if (cnt == changeCnt) {
        if (answer == "" || stoi(s) > stoi(answer)) {
            answer = s;
        }
        return;
    }
 
    //각 자리마다 바꾸기
    for (int i = 0; i < s.length(); i++) {
        if (i == index) {
            go(index + 1, cnt);
        }
        else {
            swap(s, index, i);
            go(index + 1, cnt + 1);
            swap(s, i, index);
        }
    }
}
 
//문자열에 같은 숫자가 있는지 없는지 판단
bool hasSame(string str) {
    for (int i = 0; i < str.length() - 1; i++) {
        char check = str[i];
        for (int j = i + 1; j < str.length(); j++) {
            if (check == str[j]) {
                return true;
            }
        }
    }
    return false;
}
 
int main() {
    int test_case;
    int T;
 
    cin >> T;
 
    for (test_case = 1; test_case <= T; test_case++) {
 
        //초기화
        answer = "";
        maxS = "";
        minChangeCnt = -1;
        changeCnt = 0;
 
        //입력
        cin >> s >> change;
 
        //maxS : s로 만들 수 있는 최대값(s:12345 -> maxS:54321)
        maxS = s;
        sort(maxS.begin(), maxS.end(), greater<char>());
 
        //교환 횟수 줄이기(최소 문자열 길이만큼만 바꿔도 최댓값을 만들 수 있으므로)
        changeCnt = change > s.length() ? s.length() : change;
 
        //탐색
        go(00);
 
        //교환 횟수 안에 최댓값을 만들 수 있다면
        if (minChangeCnt != -1) {
            answer = maxS;
 
            //s에 같은 숫자가 있는 경우, 같은 숫자끼리 무한 반복 -> 최댓값 유지
            //s에 같은 숫자가 없는 경우, 뒤에 두 숫자를 바꿀지 말지 결정
            if (!hasSame(s)) {
                //(교환횟수 - 최댓값을 만들 수 있는 최소교환횟수)가 홀수일 경우 뒤 두 숫자 교환
                if ((change - minChangeCnt) % 2 == 1) {
                    swap(answer, answer.length() - 2, answer.length() - 1);
                }
            }
        }
 
        //출력
        cout << "#" << test_case << " " << answer << "\n";
    }
 
    //종료
    return 0;
}

 

백트래킹에 대해 알아볼 수 있는 문제였습니다.

'알고리즘 문제풀이 > SWEA' 카테고리의 다른 글

[C++] SWEA 1215 - 회문1  (0) 2021.01.05
[C++] SWEA 1208 - Flattern  (0) 2021.01.02
[C++] SWEA 2112 - 보호 필름  (0) 2020.05.19
[C++] SWEA 2117 - 홈 방범 서비스  (0) 2020.05.19
[C++] SWEA 5656 - 벽돌 깨기  (0) 2020.05.19

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5V1SYKAaUDFAWu

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

<풀이>

1. 각 열마다 어떤 약품을 투입할 것인지 결정한다.

2. 결정된 약품을 각 열에 투입하고, 성능검사를 한다.

3. 성능검사에 통과된 약품 투입횟수 중 최솟값을 출력한다.

 

<해법>

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <iostream>
#include <cstring>
using namespace std;
 
int D, W, K;
int map[13][20];
int tmpMap[13][20];
int medicine[13];
int res;
 
void go(int index, int medicineCnt) {
 
    //사용한 약품 개수는 합격 기준보다 많을 경우 -> 탐색 필요X
    if (medicineCnt > K) {
        return;
    }
 
    //결과값보다 많은 약품을 사용할 경우 -> 탐색 필요X
    if (res >= 0 && medicineCnt > res) {
        return;
    }
 
    //약품 선택 완료 -> 종료조건
    if (index == D) {
        
        memcpy(tmpMap, map, sizeof(tmpMap));
 
        //약품 투입
        for (int i = 0; i < D; i++) {
            if (medicine[i] == -1) {
                continue;
            }
            for (int j = 0; j < W; j++) {
                tmpMap[i][j] = medicine[i];
            }
        }
 
        //보호필름 검사
        bool isAble = true;
        //각 열마다 행 탐색
        for (int i = 0; i < W; i++) {
            int cnt = 1;
            for (int j = 0; j < D - 1; j++) {
                
                //다음 행과 비교
                if (tmpMap[j][i] == tmpMap[j + 1][i]) {
                    cnt++;
                }
                else {
                    cnt = 1;
                }
 
                if (cnt == K) {
                    break;
                }
            }
 
            if (cnt < K) {
                isAble = false;
                break;
            }
        }
 
        //결과 저장
        if (isAble) {
            if (res == -1 || medicineCnt < res) {
                res = medicineCnt;
            }
        }
 
        //종료
        return;
    }
 
    //medicine[index] -> index열에 어떤 약품이 칠해지는지 저장
    //-1 : 약품X, 0 : A약품, 1 : B약품
    for (int i = -1; i <= 1; i++) {
        medicine[index] = i;
        if (i == -1) {
            go(index + 1, medicineCnt);
        }
        else {
            //약품을 칠한 경우, 사용한 약품 개수 + 1
            go(index + 1, medicineCnt + 1);
        }
    }
    return;
}
 
int main() {
 
    int test_case;
    int T;
 
    cin >> T;
 
    for (test_case = 1; test_case <= T; test_case++) {
 
        //초기화
        memset(map, 0sizeof(map));
        memset(medicine, 0sizeof(medicine));
        res = -1;
 
        //입력
        cin >> D >> W >> K;
        for (int i = 0; i < D; i++) {
            for (int j = 0; j < W; j++) {
                cin >> map[i][j];
            }
        }
 
        //약품 칠하고 보호필름 검사(재귀함수)
        go(00);
 
        //출력
        cout << "#" << test_case << " " << res << "\n";
    }
 
    return 0;
}
 

 

백트래킹에 대해 알아볼 수 있는 문제였습니다.

'알고리즘 문제풀이 > SWEA' 카테고리의 다른 글

[C++] SWEA 1208 - Flattern  (0) 2021.01.02
[C++] SWEA 1244 - 최대 상금  (0) 2020.12.31
[C++] SWEA 2117 - 홈 방범 서비스  (0) 2020.05.19
[C++] SWEA 5656 - 벽돌 깨기  (0) 2020.05.19
[C++] SWEA 5650 - 핀볼 게임  (0) 2020.05.15

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5V61LqAf8DFAWu

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

<풀이>

1. 모든 도시 좌표에서 서비스 제공을 시작한다.

2. 각 좌표에서 시작해서 서비스 영역을 넓혀가며, 그 때 마다 이윤을 구하고 최댓값을 저장한다.

3. 결과를 출력한다.

 

<해법>

1. 각 좌표에서 서비스 영역을 넓혀가는 방법.

=> 각 좌표에서 넓혀지는 서비스 영역이, 2차원 배열에서 BFS를 이용해 4방향 탐색하는 방식과 비슷하다고 생각하였습니다. 따라서 저는 위 방법을 이용하여 구현하였습니다.

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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
 
struct pos {
    //좌표
    int x, y;
};
 
//4방향
int di[] = { -1,0,1,0 };
int dj[] = { 0,1,0,-1 };
 
int N, M;
int map[20][20];
bool visited[20][20];
int res;
 
//범위 내에 있는지 판단
bool inner(int x, int y) {
    if (x < 0 || y < 0 || x >= N || y >= N) {
        return false;
    }
    return true;
}
 
int bfs(pos str) {
 
    //초기화
    memset(visited, falsesizeof(visited));
 
    queue<pos> q;
    q.push(str);
    visited[str.x][str.y] = true;
 
    int K = 0, cnt = 0, MAX = 0;
 
    while (!q.empty()) {
        int qsize = q.size();
        K++;
        
        //서비스 영역부분 탐색
        for (int i = 0; i < qsize; i++) {
            pos cur = q.front();
            q.pop();
 
            //집 개수 세기
            if (map[cur.x][cur.y] == 1) {
                cnt++;
            }
 
            //4방향 탐색
            for (int j = 0; j < 4; j++) {
                pos nxt = cur;
                nxt.x += di[j];
                nxt.y += dj[j];
 
                if (!inner(nxt.x, nxt.y)) {
                    continue;
                }
                if (visited[nxt.x][nxt.y]) {
                    continue;
                }
                
                q.push(nxt);
                visited[nxt.x][nxt.y] = true;
            }
        }
 
        //이윤 계산
        int profit = (cnt * M) - ((K * K) + (K - 1* (K - 1));
        
        //손해보지 않는 경우, 집 개수 계산
        if (profit >= 0) {
            if (cnt > MAX) {
                MAX = cnt;
            }
        }
    }
 
    return MAX;
}
 
int main() {
 
    int test_case;
    int T;
 
    cin >> T;
 
    for (test_case = 1; test_case <= T; test_case++) {
 
        //초기화
        memset(map, 0sizeof(map));
        res = 0;
 
        //입력
        cin >> N >> M;    
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                cin >> map[i][j];
            }
        }
 
        //모든 좌표마다 탐색
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                pos str = { i,j };
                int tmp = bfs(str);
 
                if (tmp > res) {
                    res = tmp;
                }
            }
        }
 
        //출력
        cout << "#" << test_case << " " << res << "\n";
    }
 
    return 0;
}
 

 

구현에 대해 알아볼 수 있는 문제였습니다.

'알고리즘 문제풀이 > SWEA' 카테고리의 다른 글

[C++] SWEA 1244 - 최대 상금  (0) 2020.12.31
[C++] SWEA 2112 - 보호 필름  (0) 2020.05.19
[C++] SWEA 5656 - 벽돌 깨기  (0) 2020.05.19
[C++] SWEA 5650 - 핀볼 게임  (0) 2020.05.15
[C++] SWEA 5644 - 무선 충전  (0) 2020.05.15

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRQm6qfL0DFAUo

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

<풀이>

1. 구슬을 떨어트릴 위치를 정한다. 모든 경우를 탐색해야 하므로, 재귀함수를 이용한다.

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
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
 
struct brick {
    //위치
    int x, y;
    //
    int cnt;
};
 
//4방향
int di[] = { -1,0,1,0 };
int dj[] = { 0,1,0,-1 };
 
int N, W, H;
int map[15][12];
int tmpMap[15][12];
int ball[4];
int res;
 
void down() {
 
    //빈칸 위에 벽돌이 있을 경우, 벽돌 내리기
    for (int i = 0; i < W; i++) {
        //가장 아래칸부터 탐색
        for (int j = H - 1; j >= 0; j--) {
            if (tmpMap[j][i] == 0) {
                //빈칸 위에 벽돌이 있는 경우 -> 빈칸과 벽돌 위치 바꾸기
                for (int k = j - 1; k >= 0; k--) {
                    if (tmpMap[k][i] > 0) {
                        tmpMap[j][i] = tmpMap[k][i];
                        tmpMap[k][i] = 0;
                        break;
                    }
                }
            }
        }
    }
}
 
void go(int index) {
     
    //종료 조건 : 떨어트릴 구슬 위치 선택 완료
    if (index == N) {
 
        //초기화
        memcpy(tmpMap, map, sizeof(tmpMap));
        int cnt = 0;
 
        //N개 구슬 떨어트리기
        for (int i = 0; i < N; i++) {
 
            queue<brick> q;
 
            //구슬 떨어트리고, 가장 처음 터지는 벽돌 큐에 담기
            for (int j = 0; j < H; j++) {
                if (tmpMap[j][ball[i]] > 0) {
                    q.push({ j,ball[i],tmpMap[j][ball[i]] });
                    tmpMap[j][ball[i]] = 0;
                    break;
                }
            }
 
            //벽돌이 모두 터질때 까지 터트리기
            while (!q.empty()) {
 
                brick cur = q.front();
                q.pop();
 
                //4방향 모두 터트리기
                for (int j = 0; j < 4; j++) {
                    brick nxt = cur;
                    //(벽돌 길이 - 1) 만큼 터트리기
                    for (int k = 0; k < cur.cnt - 1; k++) {
 
                        nxt.x += di[j];
                        nxt.y += dj[j];
 
                        //범위를 넘어섰을 경우
                        if (nxt.x < 0 || nxt.y < 0 || nxt.x >= H || nxt.y >= W) {
                            break;
                        }
                        //벽돌이 아닐경우
                        if (tmpMap[nxt.x][nxt.y] == 0) {
                            continue;
                        }
 
                        //터지는 벽돌 큐에 담기
                        nxt.cnt = tmpMap[nxt.x][nxt.y];
                        q.push(nxt);
                        tmpMap[nxt.x][nxt.y] = 0;
                    }
                }
            }
 
            //벽돌 떨어트리기
            down();
        }
 
        //결과 계산 및 저장
        for (int i = 0; i < H; i++) {
            for (int j = 0; j < W; j++) {
                if (tmpMap[i][j] > 0) {
                    cnt++;
                }
            }
        }
        if (res == -1 || cnt < res) {
            res = cnt;
        }
        return;
    }
 
    //떨어트릴 구슬 위치 저장(재귀함수)
    for (int i = 0; i < W; i++) {
        ball[index] = i;
        go(index + 1);
    }
 
    return;
}
 
int main() {
 
    int test_case;
    int T;
 
    cin >> T;
 
    for (test_case = 1; test_case <= T; test_case++) {
 
        //초기화
        memset(map, 0sizeof(map));
        memset(tmpMap, 0sizeof(tmpMap));
        memset(ball, 0sizeof(ball));
        res = -1;
 
        //입력
        cin >> N >> W >> H;
        for (int i = 0; i < H; i++) {
            for (int j = 0; j < W; j++) {
                cin >> map[i][j];
            }
        }
 
        //떨어트릴 구슬 위치 구하고, 결과값 저장
        go(0);
 
        //출력
        cout << "#" << test_case << " " << res << "\n";
    }
 
    return 0;
}
 

 

구현과 시뮬레이션에 대해 알아볼 수 있는 문제였습니다.

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRF8s6ezEDFAUo

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

<풀이>

1. 모든 출발 지점에서 모든 방향으로 핀볼을 굴립니다.

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
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <iostream>
using namespace std;
 
//북,동,남,서
int di[] = { -1,0,1,0 };
int dj[] = { 0,1,0,-1 };
 
//방향 반대로 바꾸기
int reverseDir[] = { 2,3,0,1 };
 
//블록만날때 바뀌는 방향 index
int block[6][4= {
    {0,0,0,0},
    {2,3,1,0}, //1번 블록
    {1,3,0,2}, //2번 블록
    {3,2,0,1}, //3번 블록
    {2,0,3,1}, //4번 블록
    {2,3,0,1}  //5번 블록
};
 
int N;
int map[102][102];
int res;
 
int gameStart(int startX, int startY, int startDir) {
 
    //점수
    int score = 0;
 
    //위치
    int x = startX, y = startY, dir = startDir;
 
    //시뮬레이션
    while (true) {
 
        x += di[dir], y += dj[dir];
 
        //5가지 경우(빈칸,블랙홀,벽,블록,웜홀)
 
        //1.빈칸일 경우
        if (map[x][y] == 0) {
            //시작지점으로 돌아왔을 경우 -> 종료
            if (x == startX && y == startY) {
                return score;
            }
        }
 
        //2.블랙홀일 경우 -> 종료
        else if (map[x][y] == -1) {
            return score;
        }
 
        //3.벽일 경우
        else if (map[x][y] == -2) {
            //방향 반대 전환
            dir = reverseDir[dir];
            score++;
        }
 
        //4.블록일 경우
        else if (map[x][y] >= 1 && map[x][y] <= 5) {
            //방향 전환
            dir = block[map[x][y]][dir];
            score++;
        }
 
        //5.웜홀일 경우
        else {
            //위치 변환
            bool isChanged = false;
            for (int i = 1; i <= N; i++) {
                for (int j = 1; j <= N; j++) {
                    //맵 위의 값이 같고, 좌표가 다를 경우 -> 다른 웜홀 발견
                    if ((map[i][j] == map[x][y]) && !(x == i && y == j)) {
                        x = i, y = j;
                        isChanged = true;
                        break;
                    }
                }
                if (isChanged) {
                    break;
                }
            }
        }
    }
}
 
int main() {
 
    int test_case;
    int T;
 
    cin >> T;
 
    for (test_case = 1; test_case <= T; test_case++) {
 
        //초기화
        for (int i = 0; i < 102; i++) {
            for (int j = 0; j < 102; j++) {
                map[i][j] = -2;
            }
        }
        res = 0;
 
        //입력
        cin >> N;
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) {
                cin >> map[i][j];
            }
        }
 
        //핀볼 게임판 전체 탐색
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) {
 
                //빈칸인 곳에서 핀볼 게임 시작
                if (map[i][j] == 0) {
                    //4방향 모두 굴리기
                    for (int k = 0; k < 4; k++) {
                        //gameStart(x좌표, y좌표, 방향)
                        if (gameStart(i, j, k) > res) {
                            res = gameStart(i, j, k);
                        }
                    }
                }
            }
        }
 
        //출력
        cout << "#" << test_case << " " << res << "\n";
    }
    return 0;
}
 

 

시뮬레이션에 대해 알아볼 수 있는 문제였습니다.

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRDL1aeugDFAUo&

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

<풀이>

1. 사용자 A, B의 좌표를 한번씩 이동시킨다.

2. 이동할 때 마다 사용자들과 모든 BC의 거리를 계산 후, 사용 가능한 BC의 정보를 각각 벡터에 저장한다.

3. A와 B가 사용할 모든 BC의 경우를 판단하여, 가장 큰 충전량의 합을 계산한다.

4. 결과를 출력한다.

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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
 
//구조체 : BC 정보
struct BC {
    int x, y;
    int c;
    int p;
};
 
//5방향
int di[] = { 0,-1,0,1,0 };
int dj[] = { 0,0,1,0,-1 };
 
int M, BC_cnt;
int A[101];
int B[101];
vector<BC> bc;
int res;
 
int main() {
 
    int test_case;
    int T;
 
    cin >> T;
 
    for (test_case = 1; test_case <= T; test_case++) {
 
        //초기화
        memset(A, 0sizeof(A));
        memset(B, 0sizeof(B));
        bc.clear();
        res = 0;
 
        //입력
        cin >> M >> BC_cnt;
        for (int i = 1; i <= M; i++) {
            cin >> A[i];
        }
        for (int i = 1; i <= M; i++) {
            cin >> B[i];
        }
        for (int i = 0; i < BC_cnt; i++) {
            int x, y, c, p;
            cin >> y >> x >> c >> p;
            bc.push_back({ x,y,c,p });
        }
 
        //A가 사용할 수 있는 BC, B가 사용할 수 있는 BC 저장 벡터
        vector<int> a_BC, b_BC;
 
        //A,B 초기 좌표
        int ax = 1, ay = 1, bx = 10, by = 10;
 
        //시간마다 탐색
        for (int i = 0; i <= M; i++) {
 
            a_BC.clear();
            b_BC.clear();
 
            //A좌표, B좌표
            ax += di[A[i]];
            ay += dj[A[i]];
            bx += di[B[i]];
            by += dj[B[i]];
 
            //모든 BC와 거리 구하기
            for (int j = 0; j < BC_cnt; j++) {
                int a_dist = abs(ax - bc[j].x) + abs(ay - bc[j].y);
                int b_dist = abs(bx - bc[j].x) + abs(by - bc[j].y);
 
                //사용할 수 있는 거리라면 벡터에 저장
                if (a_dist <= bc[j].c) {
                    a_BC.push_back(j);
                }
                if (b_dist <= bc[j].c) {
                    b_BC.push_back(j);
                }
            }
 
            //A와 B가 모두 사용할 수 있는 BC가 있는 경우(BC가 겹치는 경우 처리)
            if (!a_BC.empty() && !b_BC.empty()) {
 
                //두 개의 합 중 가장 큰 값 구해서 더해주기
                int maxSum = 0;
                for (int k = 0; k < a_BC.size(); k++) {
                    for (int l = 0; l < b_BC.size(); l++) {
 
                        int tmpA = bc[a_BC[k]].p;
                        int tmpB = bc[b_BC[l]].p;
 
                        if (a_BC[k] == b_BC[l]) {
                            tmpA /= 2;
                            tmpB /= 2;
                        }
 
                        int tmpSum = tmpA + tmpB;
                        if (tmpSum > maxSum) {
                            maxSum = tmpSum;
                        }
                    }
                }
                res += maxSum;
            }
            //A만 사용할 수 있는 BC가 있는 경우
            else if (!a_BC.empty()) {
                //A가 사용할 수 있는 최대값 구해서 더해주기
                int maxA = 0;
                for (int k = 0; k < a_BC.size(); k++) {
                    if (bc[a_BC[k]].p > maxA) {
                        maxA = bc[a_BC[k]].p;
                    }
                }
                res += maxA;
            }
            //B만 사용할 수 있는 BC가 있는 경우
            else if (!b_BC.empty()) {
                //B가 사용할 수 있는 최대값 구해서 더해주기
                int maxB = 0;
                for (int k = 0; k < b_BC.size(); k++) {
                    if (bc[b_BC[k]].p > maxB) {
                        maxB = bc[b_BC[k]].p;
                    }
                }
                res += maxB;
            }
        }
 
        //결과 출력
        cout << "#" << test_case << " " << res << "\n";
    }
    return 0;
}
 

 

구현에 대해 알아볼 수 있는 문제였습니다.

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5-BEE6AK0DFAVl

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

<풀이>

1. 주어지는 사람들 각각 계단을 선택한다.

2. 선택된 계단들로 나오는데 걸리는 시간을 계산하고, 그 중 가장 최소값을 출력한다.

<해법>

1. 주어지는 사람들 각각 계단 선택 방법.

=> 계단 선택은 재귀 함수를 이용하여, 모든 경우를 계산하고 선택된 계단 정보들을 저장합니다.

 

2. 선택된 계단들로 나오는 시간 계산하는 방법.

=> 저는 deque를 이용하였습니다. 계단은 2개이므로 배열로 선언해주었고, deque에 담기는 내용은 계단의 길이입니다.

시간이 증가할 때마다 deque에 담긴 내용을 1씩 감소시켜주고, 0이 될 경우 pop_front를 해주었습니다.

만약 deque의 크기가 4이상일 경우, 앞의 3개의 index의 내용만 1씩 감소시켜주었습니다.

 

3. res + 1

=> 제 코드는 문제에서 주어진 대로 구현하지 않은 단점이 있습니다. 계단에 도착한 즉시 계단 deque안으로 들어가고 값이 1감소합니다.

예를 들면, time=2 일때 계단에 도착하고 time=3일 때부터 계단을 내려가야 하는데, 제 코드는 time=2일 때부터 계단을 내려갑니다.

따라서, 마지막 결과값에 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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#include <iostream>
#include <vector>
#include <deque>
#include <cstring>
using namespace std;
 
//구조체 : 사람
struct people {
    //위치
    int x, y;
    //선택된 계단(0 or 1) 
    int stairNum;
    //선택된 계단 과의 거리
    int distance;
};
 
//구조체 : 계단
struct stair {
    //위치
    int x, y;
    //계단 길이
    int stairLength;
};
 
int N;
int map[10][10];
bool visited[10];
vector<people> p;
vector<stair> s;
int res;
 
void go(int index) {
 
    //모든 사람의 계단 선택이 완료되었을 경우 -> 종료조건
    if (index == p.size()) {
        
        //초기화
        int time = 0;
        memset(visited, falsesizeof(visited));
        deque<int> dq[2];
 
        //시간 계산
        while (true) {
            
            bool all_People_In_Stair = true;
            for (int i = 0; i < p.size(); i++) {
                if (!visited[i]) {
                    all_People_In_Stair = false;
                }
            }
 
            //모든 사람이 계단 안에 들어갔고 && 0번 계단에 사람이 없고 && 1번 계단에 사람이 없을 경우 -> 종료
            if (all_People_In_Stair && dq[0].empty() && dq[1].empty()) {
                break;
            }
 
            //각각 사람 탐색
            for (int i = 0; i < p.size(); i++) {
                //계단에 이미 들어간 사람일 경우, continue
                if (visited[i]) {
                    continue;
                }
 
                //계단에 도착하였을 시, 계단 deque에 "계단 길이" 넣어주기
                if (p[i].distance == time) {
                    if (p[i].stairNum == 0) {
                        dq[0].push_back(s[0].stairLength);
                        visited[i] = true;
                    }
                    else {
                        dq[1].push_back(s[1].stairLength);
                        visited[i] = true;
                    }
                }
            }
 
            //2개 계단 모두 탐색
            for (int i = 0; i < 2; i++) {
 
                //계단에 사람이 있다면
                if (!dq[i].empty()) {
 
                    //계단 deque에 사람이 4명 이상일 경우
                    if (dq[i].size() >= 4) {
 
                        //앞의 3명만 움직이기
                        for (int j = 0; j < 3; j++) {
                            dq[i][j]--;
                        }
                    }
                    //계단 deque에 사람이 3명 이하일 경우
                    else {
 
                        //계단에 있는 사람 전부 움직이기
                        for (int j = 0; j < dq[i].size(); j++) {
                            dq[i][j]--;
                        }
                    }
 
                    for (int j = 0; j < dq[i].size(); j++) {
 
                        //계단을 다 내려간 사람이 있을 경우
                        if (dq[i][j] == 0) {
 
                            //계단 deque에서 제거
                            dq[i].pop_front();
 
                            //index 맞춰주기
                            j--;
                        }
                    }
                }
            }
 
            //시간 증가
            time++;
        }
 
        //결과 저장
        if (res == -1 || time < res) {
            res = time;
        }
 
        //종료
        return;
    }
 
    //각 사람마다 0번 계단 또는 1번 계단 선택
    for (int i = 0; i <= 1; i++) {
        //계단 번호 저장
        p[index].stairNum = i;
        //계단 과의 거리 저장
        p[index].distance = abs(p[index].x - s[i].x) + abs(p[index].y - s[i].y);
 
        go(index + 1);
    }
    return;
}
 
int main() {
    int test_case;
    int T;
 
    cin >> T;
 
    for (test_case = 1; test_case <= T; test_case++) {
 
        //초기화
        memset(map, 0sizeof(map));
        res = -1;
        p.clear();
        s.clear();
 
        //입력
        cin >> N;
 
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                cin >> map[i][j];
 
                //사람일 경우, 사람 벡터에 저장
                if (map[i][j] == 1) {
                    p.push_back({ i,j,0,0 });
                }
                //계단일 경우, 계단 벡터에 저장
                else if (map[i][j] > 1) {
                    s.push_back({ i,j,map[i][j] });
                }
            }
        }
 
        //각 사람마다 0번 계단 또는 1번 계단 선택(재귀함수 이용) 후 시간 계산
        go(0);
 
        //출력
        cout << "#" << test_case << " " << res + 1 <<"\n";
 
        
        /*결과에 '+1'을 해준 이유는 계단에 도착한 사람이 바로 계단에 들어가서 그렇습니다*/
        /*문제에서 주어진 대로 정확히 구현하지 못한 코드입니다. 참고로만 봐주시면 감사하겠습니다 :)*/
    }
 
    return 0;
}
 
 

 

재귀함수와 구현에 대해 알아볼 수 있는 문제였습니다.

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV597vbqAH0DFAVl

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

<풀이>

1. 군집의 이동에 따라 군집의 소멸과 합쳐짐을 관리한다.

2. 해당 시간이 지난 후, 남은 미생물 수를 출력한다.

<해법>

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <iostream>
#include <vector>
using namespace std;
 
struct grp {
    int x, y;
    int cnt;
    int dir;
};
 
int di[] = { 0,-1,1,0,0 };
int dj[] = { 0,0,0,-1,1 };
 
int N, M, K;
//군집 관리 벡터
vector<grp> v;
//군집 이동 맵
vector<int> map[100][100];
 
int main() {
 
    int test_case;
    int T;
 
    cin >> T;
 
    for (test_case = 1; test_case <= T; test_case++) {
 
        //사용할 변수 초기화
        int res = 0;
        v.clear();
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                map[i][j].clear();
            }
        }
 
        //입력
        cin >> N >> M >> K;
        for (int i = 0; i < K; i++) {
            int x, y, cnt, dir;
            cin >> x >> y >> cnt >> dir;
            v.push_back({ x,y,cnt,dir });
        }
 
        //M시간 동안 반복
        while (M--) {
 
            //이동 맵 초기화
            for (int i = 0; i < K; i++) {
                if (v[i].cnt > 0) {
                    map[v[i].x][v[i].y].clear();
                }
            }
 
            //군집 이동 => 이동 맵에 저장
            for (int i = 0; i < K; i++) {
                grp tmp = v[i];
 
                if (tmp.cnt == 0) {
                    continue;
                }
                
                tmp.x += di[tmp.dir];
                tmp.y += dj[tmp.dir];
 
                //군집이 약품이 칠해진 셀에 도착할 경우
                if (tmp.x <= 0 || tmp.y <= 0 || tmp.x >= N - 1 || tmp.y >= N - 1) {
                    tmp.cnt /= 2;
                    if (tmp.dir % 2 == 0) {
                        tmp.dir--;
                    }
                    else {
                        tmp.dir++;
                    }
                }
 
                //군집에 미생물이 있을 경우만 이동 맵에 저장
                if (tmp.cnt > 0) {
                    map[tmp.x][tmp.y].push_back(i);
                }
                v[i] = tmp;
            }
 
            //이동 맵 => 군집 관리 벡터 저장
            for (int i = 0; i < K; i++) {
 
                if (v[i].cnt == 0) {
                    continue;
                }
 
                int x = v[i].x; 
                int y = v[i].y;
 
                //한 지점에 2개 이상의 군집이 모여 있을 경우
                if (map[x][y].size() > 1) {
 
                    int sum = 0;
                    int maxGrp = 0;
                    int maxCnt = 0;
 
                    for (int j = 0; j < map[x][y].size(); j++) {
                        //총 미생물 수 구하기
                        sum += v[map[x][y][j]].cnt;
 
                        //미생물 수가 가장 많은 군집의 index를 찾기
                        if (v[map[x][y][j]].cnt > maxCnt) {
                            maxGrp = map[x][y][j];
                            maxCnt = v[map[x][y][j]].cnt;
                        }
                        v[map[x][y][j]].cnt = 0;
                    }
                    v[maxGrp].cnt = sum;
                }
            }
        }
        
        //결과 저장
        for (int i = 0; i < v.size(); i++) {
            if (v[i].cnt > 0) {
                res += v[i].cnt;
            }
        }
 
        //출력
        cout << "#" << test_case << " " << res << "\n";
    }
}
 
 

구현에 대해 알아볼 수 있는 문제였습니다.

+ Recent posts