https://softeer.ai/practice/6276/history?questionType=ALGORITHM
문제 요약
- 애니팡 같은 게임... 격자안에서 선택한 색과 상/하/좌/우 색이 같은 자동차를 모두 제거 후 빈칸은 채우는 문제..
- 임의의 점을 선택 후 차량 제거, 최종적(총 3회)으로 사라진 자동차의 개수가 점수인데, 최대 점수를 출력하라고 함.....
알고리즘
- array의 row에는 세로를 넣고, col에는 가로를 넣는다 -> 이래야 자동차를 이동하기 편리할 거 같음..
- 우선 DFS & backtracking를 사용해야 할거 같음 -> DFS로 점수를 구하고, 그 점수 보다 낮으면 탐색 X => 탐색을 최소화
- 상/하/좌/우는 for문을 돌면서 범위를 벗어난 경우를 제외해서 check하는 함수를 만들어야 함
PseudoCode
1. for문을 통해 임의의 점 선택
2. 임의의 점에서 DFS 시작
3. DFS안에서 NxN 격자를 복사 후, check 함수를 통해 같은 자동차를 제거
4. 제거된 자동차 만큼 땡겨옴 (memcopy 사용 예정)
5. 다시 임의의 점 선택 후 DFS를 통해 반복
6. Back tracking을 통해 원래 격자로 복귀
7. DFS에서 시뮬레이션 회수가 충족되면 값을 비교, 비교를 통해 최종 ans를 도출
Code
#include <stdio.h>
#include <string.h>
int N, grid[45][45], ans;
void shift(int r, int sc, int ec) {
int temp[N][3*N];
for(int i=0;i<N;i++) memcpy(temp[i], grid[i], 3*N*sizeof(int));
int len = ec - sc + 1;
for(int i = sc;i<= 3*N;i++) {
if(i+ len > 3*N) grid[r][i] = 0;
else grid[r][i] = temp[r][i+len];
}
}
int modify_grid(int r, int c) {
int color = grid[r][c];
int car_remve_num = 0;
// param
int sr = r, er = r+1;
int lsc = 46, lec = -1;
int up_flag = 1, down_flag = 1;
while(up_flag || down_flag) {
// up
if(up_flag) {
if(sr < 0 || grid[sr][c] != color) {
up_flag = 0;
sr++;
}
else {
int sc = c, ec = c+1;
int left_flag = 1, right_flag = 1;
while(left_flag || right_flag) {
if(left_flag) {
if(sc <0 || grid[sr][sc] != color) {
left_flag = 0;
sc++;
}
else {
sc--;
car_remve_num++;
}
}
if(right_flag) {
if(N-1 < ec || grid[sr][ec] != color) {
right_flag = 0;
ec--;
}
else {
ec++;
car_remve_num++;
}
}
}
shift(sr, sc,ec);
lsc = (lsc > sc) ? sc : lsc;
lec = (lec > ec) ? lec : ec;
sr--;
}
}
// down
if(down_flag) {
if(N-1 < er || grid[er][c] != color) {
down_flag = 0;
er--;
}
else {
int sc = c, ec = c+1;
int left_flag = 1, right_flag = 1;
while(left_flag || right_flag) {
if(left_flag) {
if(sc <0 || grid[sr][sc] != color) {
left_flag = 0;
sc++;
}
else {
sc--;
car_remve_num++;
}
}
if(right_flag) {
if(N-1 < ec || grid[sr][ec] != color) {
right_flag = 0;
ec--;
}
else {
ec++;
car_remve_num++;
}
}
}
shift(sr, sc,ec);
lsc = (lsc > sc) ? sc : lsc;
lec = (lec > ec) ? lec : ec;
er++;
}
}
}
return (car_remve_num +(er-sr+1)*(lec-lsc+1));
}
void DFS(int r, int c, int score, int sim_cnt) {
score += modify_grid(r,c);
if(sim_cnt == 3)
{
ans = (ans > score) ? ans : score;
return;
}
int temp[N][3*N];
for(int i=0;i<N;i++) memcpy(temp[i], grid[i], 3*N*sizeof(int));
for(int i=0;i<N;i++) {
for(int j=0;j<N;j++) {
DFS(i,j,score, sim_cnt+1);
// back traking
for(int i=0;i<N;i++) memcpy(grid[i], temp[i], 3*N*sizeof(int));
}
}
}
int main() {
// input data
scanf("%d", &N);
int TN = 3*N;
for(int i=0;i<TN;i++) {
for(int j=0;j<N;j++) scanf("%d", &grid[j][TN-1-i]);
}
// copy
int temp[N][3*N];
for(int i=0;i<N;i++) memcpy(temp[i], grid[i], 3*N*sizeof(int));
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++) {
DFS(i,j,0,1);
// back tracking
for(int i=0;i<N;i++) memcpy(grid[i], temp[i], 3*N*sizeof(int));
}
}
printf("%d", ans);
}
- back tracking & shift에서 문제 발생 -> 문제 해결.... 코드가 길어지니깐 엄청 햇갈림.
- Test case는 모두 맞음... 아마 시간 문제일 거 같음..
개선할 점
- 코드가 복잡할 수록 수정 하는데 어려움 => 모듈화 & 디버깅을 구현해 놓자!!
- 시간 부분에서 문제가 발생 => 현재는 완탐이기 때문에 조건을 통해서 완탐을 줄여야 함... 어떻게..?
- shift와 back tracking에서 시간 소요가 많이 되는데 이를 어떻게 해결하지...?
수정사항
- DFS & Visited를 사용해서, 이미 Check 된 부분은 건너 뜀 => 최적화(배열 복사 최소화)
- Shift 로직만 구현하면 정답일거 같음......
수정 코드
#include <stdio.h>
#include <string.h>
int N, grid[15][45], ans;
int visited[15][15];
int min_r, max_r, min_c, max_c, add;
int dir[][2] = {{1,0}, {-1,0}, {0,1}, {0,-1}};
void find_DFS(int r, int c, int color) {
add++;
grid[r][c] = 0;
min_r = (min_r < r) ? min_r : r;
max_r = (max_r > r) ? max_r : r;
min_c = (min_c < c) ? min_c : c;
max_c = (max_c > c) ? max_c : c;
for(int i=0;i<4;i++) {
int nr = dir[i][0], nc = dir[i][1];
if(grid[nr][nc] == 0 || grid[nr][nc] != color || visited[nr][nc]) continue;
visited[nr][nc] = 1;
find_DFS(nr,nc,color);
}
}
void garage_DFS(int cnt, int score) {
memset(visited, 0, sizeof(visited));
int temp[15][45];
memcpy(temp, grid,sizeof(grid));
for(int i=0;i<N;i++) {
for(int j=0;j<3*N;j++) {
if(grid[i][j] == 0 || visited[i][j]) continue;
memcpy(grid,temp,sizeof(grid));
int color = grid[i][j];
visited[i][j] = 1;
min_r = i, max_r = i, min_c = j, max_c = j;
add = 0;
find_DFS(i,j,color);
// shift left cars
if(cnt < 2) {
for(int r = min_r; r <= max_r; r++) {
for(int c = min_c; c <= max_c; c++) {
if(grid[r][c] != 0) continue;
int len = 0;
for(int i = c+1; i <3*N; i++) {
if(grid[r][i]) {
len = i-c;
break;
}
}
if(len) {
for(int i = c; i < c+len; i++) {
grid[r][i] = grid[r][i + len];
grid[r][i + len] = 0;
}
}
}
}
garage_DFS(cnt+1, score + add + (max_r-min_r+1)*(max_c-min_c+1));
}
else {
ans = (ans > score) ? ans : score;
continue;
}
}
}
}
int main() {
// input data
scanf("%d", &N);
int TN = 3*N;
for(int i=0;i<TN;i++) {
for(int j=0;j<N;j++) scanf("%d", &grid[j][TN-1-i]);
}
garage_DFS(0,0);
printf("%d", ans);
}