[소프티어 자바] 함께하는 효도
2024. 5. 24. 01:31ㆍ소프티어
[소프티어] 함께하는 효도 : https://softeer.ai/practice/7727
Softeer - 현대자동차그룹 SW인재확보플랫폼
softeer.ai
문제 조건 정리
- 상단 링크를 참고하세요.
문제를 풀기 전
- 친구가 최대 3명이라서 다행이었다.
- 혹시 각 친구가 4개가 아니라 3개 이하를 밟는 게 최선이라면 어쩌나 걱정스러웠다. -> 다행히도 아니었음
- 또 백트래킹의 지옥의 갇혀서 디버깅을 할 준비를 했다.
코드
package softeer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class 함께하는효도 {
private static class Pos {
int x, y;
public Pos(int x, int y) {
this.x = x;
this.y = y;
}
}
static boolean[][] visited;
static int score = 0;
static int[] dx = {1, -1, 0, 0};
static int[] dy = {0, 0, 1, -1};
// 위치(x,y)를 4개씩 묶는 리스트 (path = List<Pos>)
// 그 리스트들을 시작지점에 알맞게 묶는 리스트 (List<path>)
static List<List<Pos>> dfsList = new ArrayList<>();
static List<Integer> weights = new ArrayList<>();
static int[][] map;
static int n, m;
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stringTokenizer = new StringTokenizer(bufferedReader.readLine(), " ");
n = Integer.parseInt(stringTokenizer.nextToken());
m = Integer.parseInt(stringTokenizer.nextToken());
map = new int[n][n];
List<Pos> friends = new ArrayList<>();
for (int i = 0; i < n; i++) {
stringTokenizer = new StringTokenizer(bufferedReader.readLine(), " ");
for (int j = 0; j < n; j++) {
map[i][j] = Integer.parseInt(stringTokenizer.nextToken());
}
}
for (int i = 0; i < m; i++) {
stringTokenizer = new StringTokenizer(bufferedReader.readLine(), " ");
int x = Integer.parseInt(stringTokenizer.nextToken());
int y = Integer.parseInt(stringTokenizer.nextToken());
friends.add(new Pos(x - 1, y - 1)); // -1해서 인덱스 맞추기
}
for (int i = 0; i < m; i++) {
Pos start = friends.remove(friends.size() - 1);
visited = new boolean[n][n]; // 각 친구마다 방문 배열 초기화
visited[start.x][start.y] = true;
dfs(start, new ArrayList<>(), 1, map[start.x][start.y]);
}
// 지금까지 계산된 각 친구들의 방문들을 모두 조합해보기
findMaxScore(0, 0, new boolean[dfsList.size()]);
System.out.println(score);
}
private static void dfs(Pos now, List<Pos> path, int depth, int weight) {
path.add(now);
if (depth == 4) {
dfsList.add(new ArrayList<>(path));
path.remove(path.size() - 1); // 현재 노드를 경로에서 제거
weights.add(weight);
return;
}
for (int d = 0; d < 4; d++) {
int nextX = now.x + dx[d];
int nextY = now.y + dy[d];
if (!isSafe(nextX, nextY)) continue;
if (visited[nextX][nextY]) continue;
visited[nextX][nextY] = true;
dfs(new Pos(nextX, nextY), path, depth + 1, weight + map[nextX][nextY]);
visited[nextX][nextY] = false;
}
path.remove(path.size() - 1); // 현재 노드를 경로에서 제거
}
// 두 경로가 겹치는지 체크
private static boolean isOverlap(List<Pos> path1, List<Pos> path2) {
for (Pos pos1 : path1) {
for (Pos pos2 : path2) {
if (pos1.x == pos2.x && pos1.y == pos2.y) {
return true;
}
}
}
return false;
}
// 경로들의 합 최대값 찾기
private static void findMaxScore(int idx, int currentScore, boolean[] used) {
if (idx == dfsList.size()) {
score = Math.max(score, currentScore);
return;
}
// 현재 경로를 사용하지 않는 경우
findMaxScore(idx + 1, currentScore, used);
// 현재 경로를 사용하는 경우
boolean canUse = true;
for (int i = 0; i < idx; i++) {
// 아직 선택되지 않았어야함, 또한 그와 현재 경로가 겹치면 안됨
if (used[i] && isOverlap(dfsList.get(i), dfsList.get(idx))) {
canUse = false;
break;
}
}
if (canUse) {
used[idx] = true;
findMaxScore(idx + 1, currentScore + weights.get(idx), used);
used[idx] = false;
}
}
private static boolean isSafe(int nextX, int nextY) {
return 0 <= nextX && nextX < n && 0 <= nextY && nextY < n;
}
}
문제를 풀고 난 후
결론적으로 백트래킹을 2번 하면서 각 리스트를 완벽히 관리해야 하는 문제였다.
극단적으로 어렵지는 않았지만, 내겐 여전히 힘든 스타일이다. 백트래킹은 조금만 복잡해지면 헷갈리는 것 같다.
이전에 garage game을 풀다가 이미 정신이 혼미해진 탓일지도 모른다.
참고자료가 적어서 많은 사람이 보면 좋겠다만 구글이 잘 긁어갈지 모르겠다.