≠https://programmers.co.kr/learn/courses/30/lessons/84021
코딩테스트 연습 - 3주차_퍼즐 조각 채우기
[[1,1,0,0,1,0],[0,0,1,0,1,0],[0,1,1,0,0,1],[1,1,0,1,1,1],[1,0,0,0,1,0],[0,1,1,1,0,0]] [[1,0,0,1,1,0],[1,0,1,0,1,0],[0,1,1,0,1,1],[0,0,1,0,0,0],[1,1,0,1,1,0],[0,1,0,0,0,0]] 14 [[0,0,0],[1,1,0],[1,1,1]] [[1,1,1],[1,0,0],[0,0,0]] 0
programmers.co.kr
풀이
각 조각간의 비교만 하면 됨
1. 퍼즐과 빈 공간 나누기(BFS), 위치 정보 변환
ex![]() ![]() |
2. 각 조각 비교
2-1. for : 빈 공간
2-2. for : 퍼즐
- 이미 사용한 퍼즐 구분
- 퍼즐과 빈공간의 크기가 같아야 탐색(2-3으로)
2-3. for : 회전(4)
- 완전 탐색을 이용해 현재위치의 퍼즐과 빈공간의 모든 위치를 비교, 같은 위치의 개수 계산
- 같은 위치의 개수 ≠ 빈공간의 칸 수 or 퍼즐의 칸 수
- 90도 회전 후 2-3 재실행
- 같은 위치의 개수 = 빈공간의 칸 수 or 퍼즐의 칸 수
- 현재 퍼즐의 사용정보, 결과 갱신 후 다음 빈공간에 대해 2-1로 이동
#include <vector> #include <cstring> #include <queue> using namespace std; vector<vector<pair<int, int>>> empties; vector<vector<pair<int, int>>> puzzles; bool visit[51][51]; int answer = 0; int dy[] = {0,1,0,-1}; int dx[] = { 1,0,-1,0 }; int N; vector<pair<int, int>> repos_zero(vector<pair<int, int>> pos) {//위치 백테의 기준값을 0,0으로 변환 반환 int min_i = N; int min_j = N; for (int i = 0; i < pos.size(); i++) { min_i = min_i > pos[i].first ? pos[i].first : min_i; min_j = min_j > pos[i].second ? pos[i].second : min_j; } for (int i = 0; i < pos.size(); i++) { pos[i].first -= min_i; pos[i].second -= min_j; } return pos; } vector<pair<int, int>> bfs(vector<vector<int>> &map, int value, int i, int j) {//해당 map에서 값에 맞는 위치를 벡터에 저장 반환 visit[i][j] = true; vector<pair<int, int>> v; queue<pair<int, int>> q; q.push(make_pair(i, j)); v.push_back(make_pair(i, j)); while (!q.empty()) { int y = q.front().first; int x = q.front().second; q.pop(); for (int d = 0; d < 4; d++) { int ny = y + dy[d]; int nx = x + dx[d]; if (ny < 0 || nx < 0 || ny >= N || nx >= N)continue; if (visit[ny][nx] || map[ny][nx] != value)continue; visit[ny][nx] = true; q.push(make_pair(ny, nx)); v.push_back(make_pair(ny, nx)); } } return v; } void rot(vector<pair<int, int>> &pos) {//시계방향 90도 회전 int row = 0; for (int i = 0; i < pos.size(); i++) { row = row < pos[i].first ? pos[i].first : row; } for (int i = 0; i < pos.size(); i++) { int y = pos[i].first; int x = pos[i].second; pos[i].first=x; pos[i].second = row - y; } } void matching() { vector<bool> puzzle_visit(puzzles.size(), false); for (vector<pair<int, int>> empty : empties) { for(int puzzle_idx=0; puzzle_idx<puzzles.size(); puzzle_idx++){ if (puzzle_visit[puzzle_idx])continue; //이미 사용한 퍼즐이면 pass vector<pair<int, int>> puzzle = puzzles[puzzle_idx]; if (empty.size() != puzzle.size())continue; //퍼즐 조각 개수와 빈 영역의 칸 수가 같아야함 bool flag = false; for (int r = 0; r < 4; r++) { int k = 0; for (int i = 0; i < empty.size(); i++) {//퍼즐과 빈칸 위치 비교 for (int j = 0; j < puzzle.size(); j++) { if (empty[i].first == puzzle[j].first && empty[i].second == puzzle[j].second) { k++; continue; } } } if (k != empty.size()) {// 같은 위치인 갯수가 현재 빈칸의 칸수와 같지 않으면 90도 회전 후 다시 비교 rot(puzzle); continue; } //해당 위치에 퍼즐 조각을 채울 수 있기때문에 정보갱신 후 회전, 퍼즐 조각의 for문을 break answer += empty.size(); puzzle_visit[puzzle_idx] = true; flag = true; break; } if (flag)break; } } } int solution(vector<vector<int>> game_board, vector<vector<int>> table) { N = game_board.size(); //빈 공간 나누기 + (0,0) 기준으로 위치 변환 for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { if (game_board[i][j] == 0 && !visit[i][j]) empties.push_back(repos_zero(bfs(game_board, 0, i, j))); } } //퍼즐조각 나누기 + (0,0) 기준으로 위치 변환 memset(visit, false, sizeof(visit)); for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { if (table[i][j] == 1 && !visit[i][j]) puzzles.push_back(repos_zero(bfs(table, 1, i, j))); } } matching(); return answer; }
'알고리즘' 카테고리의 다른 글
Programmers - 로또의 최고 순위와 최저 순위(C++) (0) | 2021.09.29 |
---|---|
Programmers - 최소직사각형(C++) (0) | 2021.09.29 |
BOJ 2467 - 용액(C++) (0) | 2021.09.15 |
Programmers - 직업군 추천하기 (0) | 2021.09.15 |
Programmers - 상호평가 (0) | 2021.09.14 |
댓글