https://programmers.co.kr/learn/courses/30/lessons/64063

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

먼저 깔끔한 문제풀이 설명은 카카오 테크 블로그에서 볼 수 있다.

https://tech.kakao.com/2020/04/01/2019-internship-test/

 

2019 카카오 개발자 겨울 인턴십 코딩 테스트 문제 해설

“2019년 카카오 개발자 겨울 인턴십” 공개 채용을 위한 1차 코딩 테스트가 지난 2019년 11월 9일 오후 2시부터 6시까지 총 4시간에 걸쳐 진행되었습니다. ’19년 신입공채 1차 코딩 테스트 시에 7문제가 출제되고 5시간의 풀이 시간이 주어졌던 것과는 달리 이번 인턴 코딩 테스트는 5문제가 출제되고 4시간의 풀이 시간이 주어졌습니다. 인턴의 경우 신입 공채와는 달리 인턴 과정을 통해 추가 […]

tech.kakao.com

 

 

효율성 테스트가 있는 문제로 k의 범위가 크기 때문에 방을 하나하나 순차적으로 검사해주면 효율성 테스트에 실패한다.

효율성을 통과하는 방법은 위의 카카오 테크 블로그에 그림과 함께 굉장히 잘 설명되어있는데, 

요청한 방이 빈방이라면 바로 배정하고 배정된 방이 바로 다음 방을 가리키도록 해준다.

요청한 방이 빈방이 아니라면 그 방이 가리키는 다음 방을 계속 찾아가며 빈방을 찾는다.

이 방법은 Union-Find 알고리즘을 사용해서 효율적으로 구현할 수 있다. 부모 노드가 다음 빈 방의 번호 값을 가지도록 해주면 된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <string>
#include <vector>
#include <map>
using namespace std;
 
map<long longlong long> m;
 
long long getNextEmptyRoom(long long num) {
    if (m[num] == 0return num;
    return m[num] = getNextEmptyRoom(m[num]);
}
 
 
vector<long long> solution(long long k, vector<long long> room_number) {
    vector<long long> answer;
 
    for (long long num : room_number) {
        long long emptyRoom = getNextEmptyRoom(num);
        answer.push_back(emptyRoom);
        m[emptyRoom] = emptyRoom + 1;
    }
 
    return answer;
}
Colored by Color Scripter
 

 

https://programmers.co.kr/learn/courses/30/lessons/64064

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

먼저 깔끔한 문제풀이 설명은 카카오 테크 블로그에서 볼 수 있다.

https://tech.kakao.com/2020/04/01/2019-internship-test/

 

 

 

당첨에서 제외되어야 할 제재 아이디 목록이 몇 가지 경우의 수가 가능한 지를 구해야하는데 id배열의 크기가 8 이하이므로 모든 경우를 구해봐도 된다.

 

 

 

먼저 각 불량 아이디에 대해 모든 응모 아이디와 비교하여, 매핑될 수 있는 응모 아이디를 찾아 각각의 응모 아이디에 매핑되는 경우를 조합해준다. 불량 아이디와 매핑 될 수 있는 응모 아이디는 불량 아이디의 *부분을 제외한 모든 문자가 일치해야 하고 문자열의 길이도 같아야 한다.

 

응모 아이디를 제재목록으로 만들어주는 방법은 응모 아이디의 인덱스를 문자열로 만든 후에 이전 제재 목록 문자열과 합쳐서 넘겨주는 방법으로 구현했다.

 

문제에 나온 첫 번째 예시로 예를 들어보면 

user_id banned_id

 ["frodo", "fradi", "crodo", "abc123", "frodoc"]

["fr*d*", "abc1**"]

user_id

frodo와 abc123을 선택하는 경우는 각각 인덱스가 0과 3이므로 "03"

fradi와 abc123을 선택하는 경우는 각각 인덱스가 1과 3이므로 "13"이 된다.

 

 

그리고 제재 아이디 목록은 순서가 상관없으므로 이 문자열을 정렬해준 후 set에 넣어줘서 중복을 제거해줬다.

최종적으로 set의 크기가 정답이 된다.

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
#include <string>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
 
bool check[8];
int blen, ulen;
set<string> s;
 
void solve(int index, string res, vector<string> user_id, vector<string> banned_id) {
    if (index == blen) {
        //불량 사용자의 아이디가 이벤트 응모자 아이디와 모두 매핑되어 제재목록이 다 만들어졌다면
        sort(res.begin(), res.end());
        s.insert(res);
        return;
    }
 
 
    string bid = banned_id[index];
    int bidlen = bid.size();
 
    //각 응모자 아이디와 index번째 불량 사용자 아이디를 비교한다.
    for (int i = 0; i < ulen; i++) {
        string uid = user_id[i];
 
        //이벤트 응모자 아이디와 불량 사용자 아이디의 길이가 다르다면 continue
        if (uid.size() != bidlen) continue;
        //i번째 응모아이디가 이미 불량 사용자의 아이디와 매핑된 경우 continue
        if (check[i]) continue;
 
 
        bool flag = true;
        //*을 제외한 문자들이 같은지 검사
        for (int j = 0; j < bidlen; j++) {
            if (bid[j] == '*'continue;
 
            //문자가 하나라도 다르면 매핑될 수 없다.
            if (uid[j] != bid[j]) {
                flag = false;
                break;
            }
        }
 
 
        //불량 사용자의 아이디와 별을 제외한 부분이 같은 경우
        if (flag) {
            //i번째 사용자 아이디는 index번째 불량아이디에 매핑된 것으로 체크하고 다음 불량아이디를 경우를 탐색한다.
            check[i] = true;
            solve(index + 1, res + to_string(i), user_id, banned_id);
 
            //index번째 불량 아이디에 매핑 될 수 있는 다른 사용자 아이디를 위해 현재 i번은 다시 false로 체크
            check[i] = false;
        }
    }
}
 
 
int solution(vector<string> user_id, vector<string> banned_id) {
    int answer = 0;
 
    ulen = user_id.size();
    blen = banned_id.size();
 
    solve(0"", user_id, banned_id);
    answer = s.size();
 
    return answer;
}
Colored by Color Scripter
 

 

https://programmers.co.kr/learn/courses/30/lessons/64065

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

먼저 깔끔한 문제풀이 설명은 카카오 테크 블로그에서 볼 수 있다.

https://tech.kakao.com/2020/04/01/2019-internship-test/

 

 

 

튜플이 (2, 1, 3)인 경우 문제 조건에 따라 집합으로 표현하면 다음과 같이 된다.

{{2}, {2, 1}, {2, 1, 3}} 

또한, 문제에서도 나와 있듯이 집합의 원소는 순서가 바뀌어도 상관없으므로

{{1,2}, {3, 1, 2}, {2}} 와 같이 표현해도 튜플 (2, 1, 3)을 나타낸다.

하지만 집합으로부터 튜플을 찾기 위해서는 {{2}, {2, 1}, {2, 1, 3}} 와 같이 원소의 개수가 작은 순으로 정렬되어 있어야 한다.

 

 

 

1. 우선 집합이 문자열로 주어지므로 파싱해서 같은 원소끼리 벡터에 넣어준다.

위의 {{1,2}, {3, 1, 2}, {2}} 로 예시를 들면, 원소들을 넣은 벡터를 다시 벡터에 넣어줘서

아래와 같이 2차원 벡터가 되도록 만들어준다.

vector<vector<char>> tmp = {{1,2}, {3, 1, 2}, {2}};

c++로 하다 보니까 문자열 파싱이 조금 번거롭긴 하지만 { }, 쉼표( , ) , 숫자를 각각 구분해주면 된다.

숫자는 110처럼 한 자릿수가 아닐 수도 있으므로 쉼표가 나오기 전까지 하나의 숫자로 만들어주어야 한다. (이전의 수에 곱하기 10을 하고 현재수를 더해준다)

{ 인 경우는 따로 의미가 없어서 그냥 continue로 넘어가 주고

} 인 경우에 하나의 원소가 끝난 것이므로 벡터에 원소를 넣어주고 원소들을 넣어줬던 벡터를 다시 2차원 벡터에 넣어준다. 이때, 나중에 크기 순으로 정렬하기 위해서 원소들을 넣어줬던 벡터의 사이즈와 벡터를 함께 pair로 넣어준다.

vector < pair<int, vector<int> > > vt;

pair를 사용하면 정렬했을 때 pair의 첫 번째 값을 기준으로 먼저 정렬되기 때문에 이렇게 구현했지만, 크기를 기준으로 정렬하는 compare함수를 구현해서 정렬할 때 넣어줘도 된다.

 

 

 

2. 위에서도 언급했지만 순서가 섞여있는 집합을 {{a1}, {a1, a2}, {a1, a2, a3}, {a1, a2, a3, a4},... {a1, a2, a3, a4,..., an}}의 순서로 만들어 주어야 (a1, a2, a3, ..., an)의 튜플을 나타내는 원소를 쉽게 찾을 수 있는데, 그러기 위해서는 크기(원소가 들어가 있는 개수)를 기준으로 정렬해주면 된다.

위의 {{1,2}, {3, 1, 2}, {2}} 로 예시를 들면 크기로 정렬했을 때, {{2}, {2, 1}, {2, 1, 3}} 가 된다.

({2}는 1개이므로 크기가 1, {2, 1}은 2개이므로 크기가 2)

 

 

 

3. 마지막으로는 set을 이용하여 중복 체크를 해줬다. 벡터를 탐색하며 set에 없다면 set에 추가하고 answer에도 추가해줘서 튜플의 원소로 추가해준다.

 

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 <string>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
 
vector<int> solution(string s) {
    vector<int> answer;
 
    vector<int> tmp;
    vector < pair<intvector<int> > > vt;
 
    int size = s.size();
    int num = 0;
 
//양끝 괄호는 무시하고 시작
    for (int i = 1; i < size - 1; i++) {
        if (s[i] == '{'continue;
 
        if (s[i] == '}') {
            tmp.push_back(num);
 
            //원소를 넣어줬던 tmp벡터를 vt벡터에 tmp벡터의 크기와 pair로 같이 넣어준다.
            vt.push_back(make_pair(tmp.size(), tmp));
            
            //num은 0으로 초기화하고 다음 원소를 넣어주기 위해 tmp벡터도 초기화
            num = 0;
            tmp.clear();
        }
        else if (s[i] == ',') {
            if (s[i - 1== '}'continue//이전 원소와 구분하는 쉼표라면 넘어간다.
            
            //숫자가 만들어졌으므로 벡터에 넣어주고 num은 0으로 초기화
            tmp.push_back(num);
            num = 0;
        }
        else {
            //원소(숫자)인 경우
            num *= 10;
            num += (s[i] - '0');
        }
    }
 
    sort(vt.begin(), vt.end());
 
    set<int> res;
    for (pair<intvector<int>> p : vt) {
        //p.first: 벡터 크기, p.second: 원소 값
        for (int num : p.second) {
            //원소가 중복되지 않는다면 set에 추가해주고, answer 벡터에도 추가해준다.
            if (res.find(num) == res.end()) {
                res.insert(num);
                answer.push_back(num);
            }
        }
    }
 
 
    return answer;
}
Colored by Color Scripter
 

https://programmers.co.kr/learn/courses/30/lessons/64061

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

먼저 깔끔한 문제풀이 설명은 카카오 테크 블로그에서 볼 수 있다.

https://tech.kakao.com/2020/04/01/2019-internship-test/

 

 

인형을 바구니에 쌓는 것을 스택을 이용해서 구현해준다.

터트려져 사라진 인형의 개수를 구하는 것이므로 터질 때마다 정답에 2씩 더 해주면 된다.

처음에 문제를 제대로 안 읽어서 바구니에 남아있는 인형이 정답인 줄 알고 왜 정답이 안 나오지 하고 있었다...

 

 

 

먼저 moves에 있는 인형을 뽑을 위치는 1부터 시작하므로 인덱스로 사용하기 위해서 1을 빼주고 사용한다.

그리고 해당 위치에서 인형이 있는 곳까지 아래로 쭉쭉 내려간다.

문제 조건에 따라 인형을 발견하지 못하면 그냥 다음 뽑을 위치로 넘어가면 되고, 집어 올린 인형과 바구니 위의 가장 위에 있는 인형을 비교해준다.

 

 

 

바구니(스택)의 가장 위에 있는 인형현재 뽑은 인형 같다면 가장 위에 있는 인형을 스택에서 pop 해주고 정답에 2를 더해준다.

같지 않다면 그냥 뽑은 인형을 바구니(스택)에 push 해준다.

 

 

스택에 쌓이든 터져서 사라지든 일단 크레인으로 잡혀서 왔으므로 원래 있던 자리는 0으로 만들어서 빈칸으로 만들어주고 다음 위치로 크레인을 작동시키기 위해서 아래칸으로의 탐색은 중단한다.

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
#include <string>
#include <vector>
#include <stack>
using namespace std;
 
int solution(vector<vector<int>> board, vector<int> moves) {
    int answer = 0;
 
    stack<int> stk;
    int n = board.size();
    
    for (int num : moves) {
        num -= 1;    
        for (int i = 0; i < n; i++) {
            if (board[i][num] == 0continue;
 
            if (!stk.empty() && stk.top() == board[i][num]) {
                stk.pop();
                answer += 2;
            }
            else {
                stk.push(board[i][num]);
            }
 
            board[i][num] = 0;
            break;
        }
    }
 
    return answer;
}
Colored by Color Scripter
 

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

 

18809번: Gaaaaaaaaaarden

첫째 줄에 정원의 행의 개수와 열의 개수를 나타내는 N(2 ≤ N ≤ 50)과 M(2 ≤ M ≤ 50), 그리고 초록색 배양액의 개수 G(1 ≤ G ≤ 5)와 빨간색 배양액의 개수 R(1 ≤ R ≤ 5)이 한 칸의 빈칸을 사이에 두고 주어진다. 그 다음 N개의 줄에는 각 줄마다 정원의 각 행을 나타내는 M개의 정수가 한 개의 빈 칸을 사이에 두고 주어진다. 각 칸에 들어가는 값은 0, 1, 2이다. 0은 호수, 1은 배양액을 뿌릴 수 없는 땅, 2는 배양

www.acmicpc.net

백준에서 BaaaaaaaaaaarkingDog님이 코딩 테스트 대비 모의고사로 출제하신 완전 탐색+bfs문제이다.

대회가 열렸을 때 들어가서 풀어봤는데 재밌었다. 처음 제출했을때 시간초과가 나서 당황했는데 쓸데없는 작업을 줄여줬더니 통과했다

(꽃이 피는 곳을 저장해놓은 배열을 나중에 처음부터 끝까지 확인해서 꽃의 수를 세줬었는데, 꽃이 필때 꽃을 바로 세는 걸로 바꿔줬다)

 

 

다른 한 문제는 18808 스티커 붙이기(문제 링크)이다. (18808 스티커 붙이기 풀이 링크)

풀이 코드는  BaaaaaaaaaaarkingDog님의 블로그에서도 볼 수 있다.

 

 

 

나는 다음과 같은 방법으로 풀었다.

  1. 정원의 정보를 입력받을 때, 값이 2 (배양액을 뿌릴 수 있는 땅)이면 벡터에 넣어놓는다.
  2. 앞에서 저장해논 배양액을 뿌릴 수 있는 땅들에 대해 배양액을 뿌리지 않는 경우 / 초록색 배양액을 뿌리는 경우 / 빨간색 배양액을 뿌리는 경우를 모두 골라준다. 배양액을 뿌리는 경우에는 뿌리는 배양액의 수 - 1을 매개변수로 넘기고 뿌리지 않는 경우는 배양액의 수를 그대로 넘긴다.
    • 이때 백트랙킹으로 시간을 줄여줘야 하므로
    • 남은 배양액의 수가 남아있는 배양액을 뿌릴 수 있는 땅보다 많으면 안 되므로 더 이상 탐색을 진행하지 않는다.(배양액을 남김없이 사용해야 하고, 땅에 배양액 2개를 사용할 수 없으므로)
    • 초록색과 빨간색 배양액을 둘 다 모두 사용했다면 남은 땅의 경우의 수를 더 정해주지 않고 바로 bfs로 배양액을 퍼뜨려준다.
  3. bfs를 진행할 때에는 초록색 배양액과 빨간색 배양액을 각각 큐에 넣어서 따로 bfs를 진행해주는데, 도착한 시간을 저장하는 배열도 각각 사용한다. 또한, 각각의 큐 사이즈만큼씩 진행해서 bfs를 단계별로 진행한다.(각 초마다 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
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
186
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
 
int ans;
int n, m, g, r;
int brownSoilSize; //배양액을 뿌릴 수 있는 땅의 수
int map[50][50];
int gtime[50][50]; //초록색 배양액이 퍼진 시간을 저장
int rtime[50][50]; //빨간색 배양액이 퍼진 시간을 저장
bool flower[50][50]; //꽃이 피었는지 체크
 
int dx[] = { 0,0,1,-1 };
int dy[] = { 1,-1,0,0 };
 
vector<pair<intint> > brownSoil; //배약액을 뿌릴 수 있는 땅의 좌표를 저장
 
vector<pair<intint> > green; //초록색 배양액을 뿌릴 좌표를 저장
vector<pair<intint> > red; //빨간색 배양액을 뿌릴 좌표를 저장
 
 
void bfs() {
    queue<pair<intint> > gq;
    queue<pair<intint> > rq;
 
    //시간을 -1로 초기화
    memset(gtime, -1sizeof(gtime));
    memset(rtime, -1sizeof(rtime));
 
    memset(flower, falsesizeof(flower));
 
 
    //초록색 배양액을 뿌린 땅과 빨간색 배양액을 뿌린 땅을 각각 큐에 넣어준다.
    for (pair<intint> p : green) {
        gq.push(make_pair(p.first, p.second));
        gtime[p.first][p.second] = 0;
    }
    for (pair<intint> p : red) {
        rq.push(make_pair(p.first, p.second));
        rtime[p.first][p.second] = 0;
    }
 
    int fcnt = 0;
    int gqsize;
    int rqsize;
    int x, y, nx, ny;
    while (!gq.empty() || !rq.empty()) {
        gqsize = gq.size();
        rqsize = rq.size();
 
        //초록색 배양액 먼저 bfs
        while (gqsize--) {
            x = gq.front().first;
            y = gq.front().second;
            gq.pop();
 
            //이미 꽃이 피어난 땅은 배양액이 퍼뜨려지지 않는다
            if (flower[x][y]) continue;
 
            for (int k = 0; k < 4; k++) {
                nx = x + dx[k];
                ny = y + dy[k];
 
                //범위 체크
                if (nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
                //방문 체크
                if (gtime[nx][ny] != -1continue;
                //호수인지 체크
                if (map[nx][ny] == 0continue;
 
 
                //빨간색 배양액이 이미 있는 곳인지 체크
                if (rtime[nx][ny] != -1continue;
 
                //위의 조건을 모두 통과했다면 배양액이 퍼진다
                gtime[nx][ny] = gtime[x][y] + 1;
                gq.push(make_pair(nx, ny));
            }
 
        }
 
        
        //빨간색 배양액 bfs
        while (rqsize--) {
            x = rq.front().first;
            y = rq.front().second;
            rq.pop();
 
            for (int k = 0; k < 4; k++) {
                nx = x + dx[k];
                ny = y + dy[k];
 
                //범위체크
                if (nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
                //방문체크
                if (rtime[nx][ny] != -1continue;
                //호수인지 체크
                if (map[nx][ny] == 0continue;                
 
                if (gtime[nx][ny] == -1) {
                    //초록색 배양액이 있는지 체크
                    rtime[nx][ny] = rtime[x][y] + 1;
                    rq.push(make_pair(nx, ny));
                }
                else if (gtime[nx][ny] == rtime[x][y] + 1) {
                    //초록색 배양액이 있지만 동시에 도착한다면
 
                    //꽃이 핀다.
                    flower[nx][ny] = true;
                    rtime[nx][ny] = rtime[x][y] + 1;
 
                    //꽃의 개수 증가
                    fcnt++;
                }
        
            }
 
        }
 
 
    }
 
    //피울 수 있는 꽃의 최대개수를 저장
    if (ans < fcnt) ans = fcnt;
}
 
 
void select(int index,  int gcnt, int rcnt) {
    //남은 배양액의 수가 남아있는 배양액을 뿌릴 수 있는 땅보다 많으면 안된다(배양액을 남김없이 사용해야 하므로)
    if (gcnt + rcnt > (brownSoilSize - index)) return;
    if (gcnt == 0 && rcnt == 0) {
        //배양액을 모두 골랐다면 bfs로 배양액을 뿌려준다.
        bfs();
        return;
    }
    if (index == brownSoilSize) return;
 
    int x = brownSoil[index].first;
    int y = brownSoil[index].second;
 
    //index번째 땅에 배양액을 뿌리지 않는 경우
    select(index + 1, gcnt, rcnt);
 
    //index번째 땅에 초록색 배양액을 뿌리는 경우
    if (gcnt > 0) {
        green.push_back(make_pair(x, y));
        select(index + 1, gcnt - 1, rcnt);
        green.pop_back();
    }
        
    //index번째 땅에 빨간색 배양액을 뿌리는 경우
    if (rcnt > 0) {
        red.push_back(make_pair(x, y));
        select(index + 1, gcnt, rcnt - 1);
        red.pop_back();
    }
 
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    ans = 0;
    cin >> n >> m >> g >> r;
 
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> map[i][j];
            //배양액을 뿌릴 수 있는 땅이면 벡터에 넣어놓는다.
            if (map[i][j] == 2) brownSoil.push_back(make_pair(i, j));
        }
    }
 
 
    brownSoilSize = brownSoil.size();
    select(0, g, r);
 
    
    cout << ans << '\n';
 
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 2866. 문자열 잘라내기  (0) 2020.04.21
[BOJ] 5427. 불  (0) 2020.04.19
[BOJ] 18808. 스티커 붙이기  (0) 2020.03.23
[BOJ] 17822. 원판 돌리기  (0) 2020.03.16
[BOJ] 10757. 큰 수 A + B  (0) 2020.03.10

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

 

18808번: 스티커 붙이기

혜윤이는 최근에 다양한 대회를 참여하면서 노트북에 붙일 수 있는 스티커들을 많이 받았다. 스티커는 아래와 같이 사각 모눈종이 위에 인쇄되어 있으며, 스티커의 각 칸은 상하좌우로 모두 연결되어 있다. 또한 모눈종이의 크기는 스티커의 크기에 꼭 맞아서, 상하좌우에 스티커가 포함되지 않는 불필요한 행이나 열이 존재하지 않는다. 아래는 올바른 모눈종이의 예시이다. 주황색 칸은 스티커가 붙은 칸을, 하얀색 칸은 스티커가 붙지 않은 칸을 나타낸다. 반면 아래는 올바

www.acmicpc.net

백준에서 BaaaaaaaaaaarkingDog님이 코딩 테스트 대비 모의고사로 출제하신 시뮬레이션 문제이다. 대회가 열렸을 때 들어가서 풀어봤는데 재밌었다. 총 두 문제였는데 나머지 한 문제는 18809번 Gaaaaaaaaaarden (문제 링크)이다. (풀이 링크)

스티커 붙이기 문제가 좀 더 쉽다. 

 

 

 

먼저 매번

 sticker를 저장할 int배열 / 모니터에 스티커가 붙여졌는지 확인할 bool 배열 / 스티커를 90도 회전시킬 때 임시로 사용할 int 배열

이렇게 세 가지 배열을 사용하였다.

 

 

문제에서 나와있는 스티커를 붙이는 조건은 다음과 같다.

  1. 스티커를 회전시키지 않고 모눈종이에서 떼어낸다.
  2. 다른 스티커와 겹치거나 노트북을 벗어나지 않으면서 스티커를 붙일 수 있는 위치를 찾는다. 혜윤이는 노트북의 위쪽부터 스티커를 채워 나가려고 해서, 스티커를 붙일 수 있는 위치가 여러 곳 있다면 가장 위쪽의 위치를 선택한다. 가장 위쪽에 해당하는 위치도 여러 곳이 있다면 그중에서 가장 왼쪽의 위치를 선택한다.
  3. 선택한 위치에 스티커를 붙인다. 만약 스티커를 붙일 수 있는 위치가 전혀 없어서 스티커를 붙이지 못했다면, 스티커를 시계 방향으로 90도 회전한 뒤 2번 과정을 반복한다.
  4. 위의 과정을 네 번 반복해서 스티커를 0도, 90도, 180도, 270도 회전시켜 봤음에도 스티커를 붙이지 못했다면 해당 스티커를 붙이지 않고 버린다.

 

 

위의 조건에 따라 먼저 입력받은 스티커를 노트북의 위쪽부터 붙일 수 있는지 확인한다. 

(0, 0)부터 (N-R, M-C) 칸까지 각 칸을 스티커의 시작점으로 했을 때의 스티커를 붙이는 경우를 순차적으로 해보고

붙일 수 있다면 바로 그 자리에 붙인다. 문제 조건에서 스티커를 붙일 우선순위는 가장 먼저 가장 위쪽, 그다음에 가장 왼쪽이므로 일반적인 for문으로 돌리고 찾는 순간 바로 탐색을 종료하면 자연스럽게 구현할 수 있다.

 

 

 

스티커를 붙일 수 있는지는 단순히 스티커를 저장해놓은 배열모니터에 스티커가 붙어있는지 확인할 배열 비교해주면 된다.

비교할 때나 모니터에 스티커를 붙여줄 때, 확인할 모니터의 시작점을 주의해야 한다.

스티커는 매번 (0, 0)부터 검사해주면 되지만 모니터는 스티커를 붙이기 시작하는 칸부터 검사해야 하므로

스티커를 모니터의 (x, y) 칸부터 붙여본다고 한다면 스티커의 (i, j)를 확인할 때는 모니터의(i+x, j+y) 칸을 비교해주어야 한다.

 

 

 

모니터에 이미 스티커가 있는데 모눈종이 위에도 스티커가 있다면 붙일 수 없으므로 바로 false를 리턴해서 다음 경우로 넘어간다.

붙일 수 있다면 모니터에 스티커를 붙여주고 다음 스티커로 넘어간다.

 

 

 

모든 칸에서 시작해도 스티커를 붙일 수 없다면 90도 회전해서 똑같은 과정을 반복한다.

90도씩 회전시켜서 모든 경우(0도, 90도, 180도, 270도)를 해봤는데도 붙일 수 없다면 문제 조건에 따라 해당 스티커는 버린다.

 

 

90도 회전을 시킬 때는 위의 그림과 같이 tmp배열의 index를 기준으로 복사해줬다.

90도 회전하게 되면 행의 수(R)와 열의 수(C)가 되므로 for문에서 i는 C 전까지, j는 R 전까지 해주면 된다.

for문을 이용해서 tmp배열은 순차적으로 채워주면 되고, 스티커 배열은 i추가적인 변수 l 을 사용해서 위의 그림에 나와있는 순서대로 값이 들어가도록 구현했다. 코드로 보면 다음과 같다.

 

for (int i = 0; i < c; i++) {

        for (int j = 0, l = r-1; j < r; j++, l--) {

            tmparr[i][j] = sticker[l][i];

        }

    }

 

tmp배열에 모두 복사했다면 R과 C의 값을 아예 바꿔주고 tmp배열의 값을 원래 스티커 배열로 다시 옮겨준다.

 

 

 

k번의 스티커를 모두 붙여 본 후에 모니터에 스티커가 붙여져 있는지 확인하는 배열을 검사해서 최종 답을 구한다.

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
#include <iostream>
#include <cstring>
using namespace std;
 
int n, m, k;
int r, c;
 
bool map[40][40];
int sticker[10][10];
int tmparr[10][10];
 
 
void rotate() {
    memset(tmparr, 0sizeof(tmparr));
 
    //회전시킨 모양을 tmparr에 임시 저장
    for (int i = 0; i < c; i++) {
        for (int j = 0, l = r-1; j < r; j++, l--) {
            tmparr[i][j] = sticker[l][i];
        }
    }
 
    //90도 회전하므로 행과 열을 바꿔준다
    int tmp = r;
    r = c;
    c = tmp;
 
    //다시 스티커 배열에 tmparr배열을 복사
    memset(sticker, 0sizeof(sticker));
    for (int i = 0; i < r; i++) {
        for (int j = 0; j < c; j++) {
            sticker[i][j] = tmparr[i][j];
        }
    }
}
 
 
void putSticker(int x, int y) {
    for (int i = 0; i < r; i++) {
        for (int j = 0; j < c; j++) {
            //모눈 종이에서 스티커인 부분(1)을 노트북에 붙인다
            if (sticker[i][j] == 1) map[i + x][j + y] = true;
        }
    }
}
 
 
bool check(int x, int y) {
    for (int i = 0; i < r; i++) {
        for (int j = 0; j < c; j++) {
            //스티커를 붙일 곳에 이미 스티커가 붙어있다면 바로 false를 리턴
            if (map[i + x][j + y] && sticker[i][j] == 1return false;
        }
    }
    return true;
}
 
 
bool solve() {
    for (int i = 0; i <= n - r; i++) {
        for (int j = 0; j <= m - c; j++) {
            //i,j를 시작점으로 스티커를 붙여본다.
            if (check(i, j)) {
                //스티커를 붙일 수 있다면 붙이고 바로 true를 리턴
                putSticker(i, j);
                return true;
            }
        }
    }
    return false;
}
 
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    cin >> n >> m >> k;
 
    while (k--) {
        cin >> r >> c;
 
        for (int i = 0; i < r; i++) {
            for (int j = 0; j < c; j++) {
                cin >> sticker[i][j];
            }
        }
 
 
        bool flag = false;
        for (int i = 0; i < 4; i++) {
            flag = solve();
 
            //붙일 수 있는 곳이 있다면 break
            if (flag) break;
            else rotate(); //붙일 수 있는 곳이 없다면 90도 회전
        }
 
 
    }
 
 
    int ans = 0;
    //스티커가 붙어 있는 칸을 센다.
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (map[i][j]) ans++;
        }
    }
 
 
    cout << ans << '\n';
    
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 5427. 불  (0) 2020.04.19
[BOJ] 18809. Gaaaaaaaaaarden  (0) 2020.03.23
[BOJ] 17822. 원판 돌리기  (0) 2020.03.16
[BOJ] 10757. 큰 수 A + B  (0) 2020.03.10
[BOJ] 1331. 나이트 투어  (0) 2020.03.03

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

 

17822번: 원판 돌리기

반지름이 1, 2, ..., N인 원판이 크기가 작아지는 순으로 바닥에 놓여있고, 원판의 중심은 모두 같다. 원판의 반지름이 i이면, 그 원판을 i번째 원판이라고 한다. 각각의 원판에는 M개의 정수가 적혀있고, i번째 원판에 적힌 j번째 수의 위치는 (i, j)로 표현한다. 수의 위치는 다음을 만족한다. (i, 1)은 (i, 2), (i, M)과 인접하다. (i, M)은 (i, M-1), (i, 1)과 인접하다. (i, j)는 (i, j-1), (i, j

www.acmicpc.net

원판을 회전시키며 인접한 수를 비교하고, 같다면 숫자를 지우는 작업을 반복하는 시뮬레이션 문제이다.

 

 

 

T회만큼 반복하면서 x의 배수인 원판들을 모두 회전시킨 후 인접한 같은 수를 저장해놓았다가 나중에 한 번에 지워준다. (미리 지워서 0으로 만들어버리면 다른 방향으로 인접한 수를 지울 수 없다)

인접한 수 중 같은 숫자인게 없다면 원판에 있는 숫자의 평균을 구해서 평균보다 작으면 1을 증가시켜주고 크면 1을 감소시킨다. 여기서 지워진 숫자는 제외하고 평균을 구해야 한다

 

 

 

//k칸만큼 회전시키기

먼저 k칸만큼 시계방향 회전시킨 방법은 아래와 같이 했다. 예를 들어 k가 4인 경우이다.

편의상 배열은 인덱스가 1부터 시작하도록 구현했다.

 

 

원래 원판에 있던 숫자를 첫 번째부터 tmp배열의 k만큼 떨어진 곳인 5번 자리부터 복사한다. 인덱스가 배열 밖으로 넘어가면 안 되므로 작업을 tmp배열의 마지막 부분인 6번 인덱스까지만 먼저 진행한다.

 

 

 

 

그다음 아래 그림처럼 원판의 나머지 부분을 이어서 tmp배열의 처음 칸부터 k번 인덱스까지 순차적으로 채워주면 된다.

 

시계 반대 방향으로 1번 회전시킨 것은 시계 방향으로 M-1번 회전시킨 것과 같고

마찬가지로 시계 반대 방향으로 2번 회전시킨 것은 시계 방향으로 M-2번 회전시킨 것과 같으므로

같은 함수를 이용해서 회전 횟수를M-k번으로 해주면 된다.

 

 

 

//인접한 숫자 중 같은 수 찾기

 

문제에 나와있는 인접한 수의 조건은 다음과 같다.

  • (i, 1)은 (i, 2), (i, M)과 인접하다.
  • (i, M)은 (i, M-1), (i, 1)과 인접하다.
  • (i, j)는 (i, j-1), (i, j+1)과 인접하다. (2 ≤ j ≤ M-1)
  • (1, j)는 (2, j)와 인접하다.
  • (N, j)는 (N-1, j)와 인접하다.
  • (i, j)는 (i-1, j), (i+1, j)와 인접하다. (2 ≤ i ≤ N-1)

그냥 같은 원판(같은 행) 안에서 바로 양 옆이 인접한 수이고, 바로 위나 아래에 있는 원판 중에서는 같은 열이 인접한 수이다. 그래서 같은 원판 안에서는 마지막 숫자의 옆이 다시 첫 번째 숫자인 것을 처리해주어야 하지만

서로 다른 원판들의 위아래를 비교할 때는 맨 위의 원판과 맨 아래의 원판은 인접한 것이 아니므로 따로 처리해줄 필요는 없다.

 

 

 

//인접한 같은 수 지우기

또, 인접한 같은 수를 미리 지워서 0으로 만들어버리면 다른 방향으로 인접한 수와 비교할 수 없으므로 나중에 한 번에 지워줘야 한다. 그러기 위해서 인접한 같은 수를 가진 좌표들을 저장해놓아야 한다.

중복되는 좌표도 발생할 것 같아서 set을 이용하였다. 인접한 수를 찾으면 set에 원판의 위치(i, j)를 pair로 넣어주고, 나중에 set에서 한 번에 위치를 꺼내서 원판의 해당 위치의 숫자를 지워준다

(이때 나는 한쪽 방향으로만 비교하도록 구현했기 때문에 인접한 같은 두 수의 위치를 모두 넣어줬다)

 

 

 

//평균 구해서 더하고 빼주기

위에서 인접한 같은 수가 없어서 지워진 수가 하나도 없다면 문제 조건에 따라

원판에 있는 수들의 평균을 구해서(지워진 수는 제외) 평균보다 높다면 1을 빼주고 평균보다 낮다면 1을 더해준다.

c++에서 int형으로 몫을 구했다면 소수점을 제외한 몫만 저장하므로 나누어 떨어지지 않는 경우를 따로 처리해준다.

 

나누어 떨어지는 경우는 정말 값이 같은 경우이므로 값을 바꿔줄 필요가 없고

나머지가 있다면 실제 값은 몫+나머지 이므로 원판의 값이 평균보다 더 작은 것이므로 1을 더해준다.

 

 

 

//최종 답

T번의 회전이 모두 끝나면 원판의 숫자를 모두 더해준 값이 정답이다.

 

 

 

 

개인적으로 실수한 부분들 메모...

  1. 평균을 구하는 과정에서 0으로 나누는 경우가 발생하면 안 된다.
  2. 문제 조건에서 평균보다 큰 경우와 작은 경우에 대해만 나와있으므로 같은 경우에는 값이 변하지 않는다.
  3. n과 m을 또 반대로 씀... 문제에서 반대로 해놓은 것이 아니었음에도 불구하고...
  4. 문제 조건을 제대로 안 읽고, 인접한 수가 없는 경우 평균을 구해서 값을 변경시켜주는 부분을 안봄...
  5. 인접한 같은 수 두 개를 set에 넣을 때 하나만 넣어줘서 제대로 안 지워짐
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
#include <iostream>
#include <set>
using namespace std;
 
int n, m, t;
int board[51][51];
int tmp[51][51];
 
 
void rotate(int i, int count) {
    //i번 원판을 회전
 
    int index = 1;
    for (int j = count+1; j <= m; j++) {
        tmp[i][j] = board[i][index++];
    }
 
    for (int j = 1; j <= count; j++) {
        tmp[i][j] = board[i][index++];
    }
 
 
    //board로 다시 복사
    for (int j = 1; j <= m; j++) {
        board[i][j] = tmp[i][j];
    }
}
 
 
bool removeAdj() {
 
    set<pair<intint> > s;
 
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
 
            if (board[i][j] == 0continue;
 
 
            //같은 원판 비교
            if (j == m) {
                //마지막열의 다음은 첫번째열
                if (board[i][m] == board[i][1]) {
                    s.insert(make_pair(i, m));
                    s.insert(make_pair(i, 1));
                }
            }
            else {
                if (board[i][j] == board[i][j + 1]) {
                    s.insert(make_pair(i, j));
                    s.insert(make_pair(i, j + 1));
                }
            }
            
        }
    }
 
 
    //위 아래 원판 비교
    for (int j = 1; j <= m; j++) {
        for (int i = 1; i < n; i++) {
            //지워진 애는 넘어간다.
            if (board[i][j] == 0continue;
 
            //아래있는 원판과 비교
            if (board[i][j] == board[i+1][j]) {
                s.insert(make_pair(i, j));
                s.insert(make_pair(i + 1, j));
            }
        
        }
    }
 
 
    //인접한 수 중 같은게 없으면 바로 false를 리턴
    if (s.empty()) return false;
 
 
    //set에 들어있는 좌표를 사용하여 모두 지우고 true를 리턴
    set<pair<intint>> ::iterator iter;
    for (iter = s.begin(); iter != s.end(); iter++) {
        board[iter->first][iter->second] = 0;
    }
 
    return true;
}
 
void calc() {
 
    int sum = 0;
    int total = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (board[i][j] == 0continue;
 
            total += 1;
            sum += board[i][j];
        }
    }
 
    //숫자가 모두 지워져있다면 바로 리턴
    if (total == 0return;
    int avg = sum/total;
 
 
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (board[i][j] == 0continue;
 
            if (board[i][j] > avg) board[i][j] -= 1;
            else if(board[i][j] < avg) board[i][j] += 1;
            else {
                //나머지가 있다면 board[i][j]의 값이 더 작으므로 +1
                if (sum%total != 0) board[i][j] += 1;
            }
        }
    }
 
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    cin >> n >> m >> t;
 
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            cin >> board[i][j];
        }
    }
 
    int x, d, k;
    while (t--) {
        cin >> x >> d >> k;
 
 
        for (int i = 1; i <= n; i++) {
            //x의 배수인 원판을 회전
            if (i % x != 0continue;
 
            
            if (d == 0) {
                //시계방향
                rotate(i, k);
            }
            else {
                //반시계방향
                rotate(i, m - k);
            }
 
        }
        
 
        bool isRemoved = removeAdj();
        if (!isRemoved) {
            //인접한 수 중 같은게 없다면 평균과 비교해 1을 더하거나 빼준다.
            calc();
        }
    }
 
 
    //t회 후에 숫자의 총 합
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            ans += board[i][j];
        }
    }
 
 
    cout << ans << '\n';
 
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 18809. Gaaaaaaaaaarden  (0) 2020.03.23
[BOJ] 18808. 스티커 붙이기  (0) 2020.03.23
[BOJ] 10757. 큰 수 A + B  (0) 2020.03.10
[BOJ] 1331. 나이트 투어  (0) 2020.03.03
[BOJ] 4179. 불!  (0) 2020.02.17

https://programmers.co.kr/learn/courses/30/lessons/60059

 

코딩테스트 연습 - 자물쇠와 열쇠 | 프로그래머스

[[0, 0, 0], [1, 0, 0], [0, 1, 1]] [[1, 1, 1], [1, 1, 0], [1, 0, 1]] true

programmers.co.kr

lock의 크기와 key의 크기가 최대 20이므로 완전 탐색으로 해결할 수 있다.

(key를 90도씩 회전시키는 네 가지 경우) X (자물쇠에 열쇠를 맞춰보는 모든 경우)를 구해주면 된다.

 

주의할 점은 예제에는 똑같이 나와있지만 lock의 크기와 key의 크기는 다를 수 있다.

또, 열쇠를 회전시킬 때 회전시키는 함수에서 실제 key 벡터를 회전시켜야 하므로 &로 받아야 한다.

 

 

문제 조건에 따라서 열쇠는 자물쇠 밖으로 나가도 되므로

열쇠를 자물쇠 홈에 맞춰보는 모든 경우를 위해서 아래 그림과 같이 새로운 2차원 vector를 만들어줬다.

 

열쇠의 가장 오른쪽 아랫부분과 자물쇠의 가장 위쪽 부분을 맞추는 경우부터

열쇠의 가장 왼쪽 윗부분과 자물쇠의 가장 오른쪽 아래 부분을 맞추는 경우까지를 모두 해주면 되기 때문에

lock의 크기 + (key의 크기 -1)*2 크기의 벡터를 만들어주면 된다.

 

 

 

그러면 매 회전 때마다 key의 시작 부분이

(0,0)에서 시작하는 경우부터 lock의 가장 마지막 부분(boardsize-keysize)에서부터 시작하는 경우까지 해보면서

key를 board에 더해 lock부분이 모두 1인지(홈이 모두 채워졌는지)를 확인하면 된다

한 곳이라도 0이거나(비어있는 홈) 2(돌기 두 개가 만남) 이면 안되므로 바로 false를 리턴한다.

 

 

 

**기존 상태에서 먼저 열쇠를 맞춰보면 회전은 3번만 하면 된다고 생각해서

반복문을 3번만 실행하도록 했어서 한참 헤맸다;;

맞춰보는 경우는 어쨌든 4번 해야 하므로 반복문을 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
#include <string>
#include <vector>
using namespace std;
 
int keysize, locksize, boardsize;
 
void rotateKey(vector<vector<int>> &key) {
        
    vector<vector<int>> tmp(keysize, vector<int>(keysize));
 
    for (int j = keysize - 1; j >= 0; j--) {
        for (int i = 0; i < keysize; i++) {
            tmp[i][j] = key[keysize - j - 1][i];
        }
    }
 
    key = tmp;
}
 
 
bool putKey(int x, int y, vector<vector<int>> key, vector<vector<int>> board) {
     //(x, y)를 시작점으로 열쇠를 자물쇠에 맞춰본다.
 
    //key를 더한다
    for (int i = x; i < x + keysize; i++) {
        for (int j = y; j < y + keysize; j++) {
            board[i][j] += key[i - x][j - y];
        }
    }
 
 
    //좌물쇠 부분 확인
    for (int i = keysize - 1; i <= boardsize - keysize; i++) {
        for (int j = keysize - 1; j <= boardsize - keysize; j++) {
            if (board[i][j] == 1continue;
 
            //1이 아니라면 바로 false를 리턴
            return false;
        }
    }
 
 
    return true;
}
 
bool solution(vector<vector<int>> key, vector<vector<int>> lock) {
    bool answer = false;
 
    keysize = key.size();
    locksize = lock.size();
 
 
    boardsize = locksize + (keysize - 1* 2;
    vector<vector<int>> board(boardsize, vector<int>(boardsize, 0));
 
 
    //board에 lock을 미리 더해놓는다. (lock은 고정되어 있고 key를 움직일 것 이므로)
    for (int i = keysize - 1; i <= boardsize - keysize; i++) {
        for (int j = keysize - 1; j <= boardsize - keysize; j++) {
            board[i][j] = lock[i - keysize + 1][j - keysize + 1];
        }
    }
 
    //회전 방향 네번
    for (int r = 0; r < 4; r++) {
        
        for (int i = 0; i <= boardsize - keysize; i++) {
            for (int j = 0; j <= boardsize - keysize; j++) {
 
                //i,j 를 key의 시작칸으로 자물쇠 홈에 맞춰본다.
                if (putKey(i, j, key, board)) {
                    answer = true;
                    return answer;
                }
 
            }
        }
 
 
        //key 시계방향으로 90도 회전
        rotateKey(key);
 
    }
 
 
    return answer;
}
Colored by Color Scripter
 

+ Recent posts