TLE, 시간 초과에 대하여 (BOJ 14500 테트로미노)
첫번째 생각해볼 것 : 이 문제를 브루트포스로 풀 수 있을까?
테트로노미노의 모든 가짓수 (회전을 통해 다르게 보이는 것들 고려)를 다 구해서,
주어진 맵에 대고 움직이며 일일히 합을 다 구해보는 것 (convolution)
→ Q. convolution 함수 구현해볼만 한데? matrix와 kernel 인자로 받아서....
두번째 :
DFS 4번 돌려서 테트로미노 찾기 가능. 다만, ㅜ 모양의 경우 DFS로는 찾기 불가.
→ Q. len == 2 일때 따로 케이스 설정해주면 가능하려나?
ㅜ 모양을 제외한 테트로미노는 DFS로 찾고,
ㅜ 모양은 DFS 이후, ㅜ 모양의 정중앙이 현재 포인트에 오게끔 한 뒤 회전시키며 4 종류의 경우를 다 탐색.
DFS는 len 변수를 인자로 주어, len == 4 일시 끝내도록 end condition 설정.
void DFS_four(int x, int y, int sum, int len){ if (len == 4) { sum + world[x][y] // sum under current tetronomino return; } ... }
주어진 맵의 모든 포인트가 각각 시작점이 되어 DFS를 돌려야 하고,
DFS는 크기가 4인 도형을 총 28가지 찾으므로,
O(5002∗28∗4)=O(2800만)

ㅜ를 찾는 함수 'check_ah'. 현재 포인트를 기준으로 상하좌우 지점의 숫자를 일단 모두 더한 뒤, 하나씩 돌아가며 빼면서 ㅜ 모양의 회전을 구현.
O(C)
// Check ㅜ block with rotations, manually bool check_wu(int x, int y) { int sum = world[x][y]; vi side; // 상하좌우 숫자 더하기 (Boundary 만나면 continue) for (int i = 0; i < 4; i++) { int x_next = x + direction[i].first; int y_next = y + direction[i].second; // Boundary check if (!(0 <= x_next && x_next < N && 0 <= y_next && y_next < M)) continue; sum += world[x_next][y_next]; side.push_back(world[x_next][y_next]); } // Case 1. 사각형 구석 포인트 같은 경우; ㅏ 모양이 만들어지지 않음 if (side.size() <= 2) return false; // Case 2. 끝 변에 위치한 포인트; 회전 불가능 else if (side.size() == 3) { each_pt = max(each_pt, sum); return true; } // Case 3. 4가지 회전 모두 고려 for (int i = 0; i < side.size(); i++) { each_pt = max(each_pt, sum-side[i]); } return true; }
Time complexity는 무난함에도 불구하고, 계속 시간 초과가 뜸.
따라서 시도해본 방법들)
1. 불필요한 오버헤드 줄이기
- max 값 구하는데, 벡터에 값을 일일히 저장했다가 맨 마지막에 sort 하고 back() 불러서 꺼내지 말고, 단일 변수를 계속 업데이트 하기;
- 좌표를 pair로 전달하지 말고, int 변수 2개로 나눠서 전달하기
2. vector 혹은 pair 같은 container들 함수에 전달할때, parameter에 & (reference)를 붙여서 복사로 전달되지 않도록
3. main 함수의 모든 포인트 loop에서 불필요한 연산들 빼버리기 (성공)
수정 전 main loop ( /// 로 제거한 부분 나타냄)
vi max_temp; for (int i = 0; i < N; i++) { for (int j = 0; j < M; j++) { /// each_pt.clear(); memset(visited, 0, sizeof(visited)); /// visited[i][j] = 1; DFS_four(make_pair(i, j), 0, 1); // passes 'pair' // check_wu({ i,j }); // passes 'pair' // /// auto result = max_element(each_pt.begin(), each_pt.end()); max_temp.push_back(*result); /// } }
수정 후 main loop
memset(visited, 0, sizeof(visited)); each_pt = 0; for (int i = 0; i < N; i++) { for (int j = 0; j < M; j++) { visited[i][j] = 1; DFS_four(i, j, 0, 1); visited[i][j] = 0; check_wu(i, j); } }
비교적 작은 연산들이더라도 For-loop이 최대 500 x 500번이나 돌아가므로, 누적될 시 많은 시간이 소요될 수 있다.
간단하지만 의외로 헤맨 시간초과 요인 기록.
BOJ 14442 - 벽 부수고 이동하기 2
반복 연산이 엄청 많이 나타나는 BFS 큐에 custom structure 넣어서 쓰니 TLE,
tuple로 바꾸니 통과.
4. 간단한 데이터 구조 쓰기.
'<PS> > [노트]' 카테고리의 다른 글
활용의 미학 : Union-Find + BFS 짬뽕 (BOJ 3197 백조의 호수) (0) | 2021.01.06 |
---|---|
DFS, 백트래킹, 완전탐색의 관계 (BOJ 1405 미친 로봇) (0) | 2020.12.26 |
문제 쪼개기 : 대각선 x,y 분해 - 벡터 (BOJ 10158 개미) (0) | 2020.12.17 |
문자열 delimiter 분해 - strpbrk & 맞왜틀 (BOJ 2941 크로아티아 알파벳) (0) | 2020.12.16 |
Brute Force vs Dynamic Programming (0) | 2020.11.01 |