티스토리 뷰
문제
programmers.co.kr/learn/courses/30/lessons/72415
코딩테스트 연습 - 카드 짝 맞추기
[[1,0,0,3],[2,0,0,0],[0,0,0,2],[3,0,1,0]] 1 0 14 [[3,0,0,2],[0,0,1,0],[0,1,0,0],[2,0,0,3]] 0 1 16
programmers.co.kr
풀이
0. 어떤 종류의 카드를 제거한다고 할 때, 종류가 같은 카드 두 개를 찾으려고 매번 맵 전체를 순회하지않기 위해 카드의 종류별로 두 카드의 위치를 담아줍니다. [ line 86 ]
1. 모든 카드를 종류별로 제거해야하고 그 순서에 따라 움직이는 거리가 달라지기에 제거할 종류들의 순서를 next_permutation으로 구해줍니다. [ line 99 ~ 103 ]
2. 종류별로 제거한다고 할 때, 두 카드중 어떤 카드를 먼저 제거할지에 따라서도 움직이는 거리가 달라지고, 카드종류의 개수가 최대 6개이므로 모든 카드의 종류를 1번째 위치부터 탐색할지 2번째 위치부터 탐색할지 정해주는 완전탐색을 구현해줍니다. [ line 64 ~77 ]
3. 이제 찾아야할 카드의 종류, 두 가지중 먼저 찾을 순서까지 정해놨으므로 문제에서 정의한 이동방식을 bfs로 구현하여 움직이는 거리의 최소 값을 갱신해갑니다. [ line 18 ~62 ]
4. 결과적으로 시간복잡도는 $O(6! * 2^6 * 4^2)$ 정도로 해결할 수 있습니다.
코드
#include <bits/stdc++.h>
using namespace std;
#define all(x) (x).begin(),(x).end()
typedef pair<int, int> pii;
const int inf = 0x3f3f3f3f;
const int dir[4][2] = { { -1,0 },{ 1,0 },{ 0,-1 },{ 0,1 } };
int board[4][4], copy_board[4][4], l, ans, dist[4][4];
vector<int> card_number, p;
vector<pii> pos[9];
pii cursor, copy_cursor;
bool isrange(int r, int c) {
if (r < 0 || r >= 4 || c < 0 || c >= 4) return 0;
return 1;
}
int go(int idx) {
int kind = card_number[idx]; // 현재 뒤집을 카드의 종류
int seq = p[idx]; // 2가지 카드중 먼저 고를 카드
int cr, cc, nr, nc, ret = 0;
pii tar[2] = { pos[kind][seq],pos[kind][1 - seq] }; // 뽑아야하는 카드의 순서
for (int i = 0; i < 2; i++) {
queue<pii> q;
q.push({ cursor.first,cursor.second });
memset(dist, inf, sizeof(dist));
dist[cursor.first][cursor.second] = 0;
while (!q.empty()) {
tie(cr, cc) = q.front(); q.pop();
// 뽑아야하는 카드를 찾았을 때 (최단경로)
if (cr == tar[i].first && cc == tar[i].second) {
cursor = tar[i]; // 커서 옮기기
board[cr][cc] = 0; // 해당 칸 뒤집기
if (i == 0) {
ret = dist[cr][cc]; // 첫 번째 카드까지 찾는 비용을 저장해줌
break;
}
else return ret + dist[cr][cc]; // 첫 번째 카드찾는 비용 + 두 번째 카드찾는 비용
}
for (int j = 0; j < 4; j++) {
nr = cr + dir[j][0], nc = cc + dir[j][1];
if (!isrange(nr, nc)) continue;
// #1. 한 칸 이동
if (dist[cr][cc] + 1 < dist[nr][nc]) {
dist[nr][nc] = dist[cr][cc] + 1;
q.push({ nr,nc });
}
// #2. Ctrl + 방향키
while (isrange(nr, nc) && !board[nr][nc]) nr += dir[j][0], nc += dir[j][1];
if (!isrange(nr, nc)) nr -= dir[j][0], nc -= dir[j][1];
if (dist[cr][cc] + 1 < dist[nr][nc]) {
dist[nr][nc] = dist[cr][cc] + 1;
q.push({ nr,nc });
}
}
}
}
}
void comb(int idx) {
if (idx == l) {
int ret = 0;
for (int i = 0; i < card_number.size(); i++)
ret += (go(i) + 2); // 카드를 찾는 것과 별개로 enter치는건 항상 2개씩이니 이는 따로 더해줌
ans = min(ans, ret);
return;
}
for (int i = 0; i < 2; i++) {
p.emplace_back(i);
comb(idx + 1);
p.pop_back();
}
}
int solution(vector<vector<int>> Board, int r, int c) {
ans = inf;
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
board[i][j] = Board[i][j];
if (board[i][j]) {
card_number.emplace_back(board[i][j]);
pos[board[i][j]].push_back({ i,j }); // 같은 카드의 위치를 저장해둠
}
}
// 현재 보드에서 존재하는 카드들의 종류를 저장 후 중복 제거
sort(all(card_number));
card_number.erase(unique(all(card_number)), card_number.end());
// 초기 상태 저장
memcpy(copy_board, board, sizeof(copy_board));
cursor = copy_cursor = { r, c };
l = card_number.size();
do {
memcpy(board, copy_board, sizeof(board)); // 보드를 다시 초기상태로
cursor = copy_cursor; // 커서를 다시 초기상태로
comb(0); // 현재 카드의 순서에서 i번째 카드종류 v[i]를 뽑을 때 존재하는 두가지 경우에 대해 모두 탐색
} while (next_permutation(all(card_number))); // 제거할 카드 종류들의 순서를 모두 탐색
return ans;
}
'Algorithm > Programmers' 카테고리의 다른 글
[프로그래머스 월간 코드 챌린지 시즌2] 음양 더하기 (0) | 2021.04.16 |
---|---|
[프로그래머스 2021 KAKAO BLIND RECRUITMENT] 광고 삽입 (0) | 2021.04.16 |
[프로그래머스 2021 KAKAO BLIND RECRUITMENT] 합승 택시 요금 (0) | 2021.01.26 |
[프로그래머스 2021 KAKAO BLIND RECRUITMENT] 순위 검색 (0) | 2021.01.26 |
[프로그래머스 2021 KAKAO BLIND RECRUITMENT] 메뉴 리뉴얼 (0) | 2021.01.26 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 위클리 챌린지
- 프로그래머스 월간코드챌린지
- 카카오 2021
- 백준
- DP
- 누적합
- 표 편집
- BFS
- 파싱
- 2020 KAKAO BLIND RECRUITMENT
- 프로그래머스 위클리 9주차
- 카카오 2차코딩테스트
- 2021 KAKAO BLIND
- 2021 카카오 블라인드
- 2022 KAKAO BLIND RECRUITMENT
- 동적계획법
- 이분탐색
- 시뮬레이션
- 카카오 인턴십
- 카카오 표 편집
- 투포인터
- 2022 카카오 블라인드 코딩테스트
- 카카오 2020 인턴십
- Kakaoblind
- 2022 카카오블라인드
- 트리
- 유니온파인드
- 프로그래머스
- 구현
- 게임이론
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함