N
개의 방이 있으며, 각 방에는 특정한 규칙이 존재한다.1번 방
에서 시작하여 N번 방
에 도착하는 것이 목표.X
골드가 필요하며, 만약 부족하면 X
골드로 채워줌.X
골드가 필요하며, 부족하면 입장 불가. 입장 시 X
골드를 차감.목표: 1번 방에서 시작하여 N번 방
에 도달할 수 있는지 판별하는 문제.
1
부터 DFS 탐색을 수행.N
에 도달하면 Yes
, 도달하지 못하면 No
를 출력.L
) X
보다 적다면, X
로 충전.T
) X
골드보다 적다면 해당 경로 탐색 종료.X
를 차감한 후 탐색 진행.E
) visited
)true
로 체크, DFS 탐색을 진행.visited
배열을 관리하면서 DFS 탐색)import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
public class Main {
private static StringTokenizer st;
private static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
private static int N;
private static String[] map;
private static boolean isPossible;
private static boolean[] visited;
public static void main(String[] args) throws IOException {
while (setting() != 0) {
visited[1] = true;
dfs(1, 0);
System.out.println((isPossible) ? "Yes" : "No");
}
}
private static void dfs(int cur, int money) {
st = new StringTokenizer(map[cur]);
String type = st.nextToken();
int moneyValue = Integer.parseInt(st.nextToken());
List<Integer> nextPoints = new ArrayList<>();
while (st.hasMoreTokens()) {
int next = Integer.parseInt(st.nextToken());
if (next != 0) nextPoints.add(next);
}
// 🏰 방에 입장할 수 있는 조건
if (type.equals("L")) {
if (money <= moneyValue) money = moneyValue; // 골드가 부족하면 충전
} else if (type.equals("T")) {
if (money < moneyValue) return; // 골드 부족하면 이동 불가
money -= moneyValue; // 골드 차감
}
// 도착점 확인 (N번 방 도달)
if (cur == N) {
isPossible = true;
return;
}
// 다음 방으로 이동
for (int nextPoint : nextPoints) {
if (visited[nextPoint]) continue;
visited[nextPoint] = true;
dfs(nextPoint, money);
visited[nextPoint] = false;
}
}
private static int setting() throws IOException {
N = Integer.parseInt(br.readLine());
if (N == 0) return N;
isPossible = false;
map = new String[N + 1];
visited = new boolean[N + 1];
for (int i = 1; i < N + 1; i++) {
map[i] = br.readLine();
}
return N;
}
}
기능 | 설명 |
---|---|
dfs(cur, money) | 현재 방 cur 에서 money 를 가지고 탐색 |
visited[] | 방문 여부를 체크하여 무한 루프 방지 |
setting() | 입력을 받아서 map[] 배열에 저장 |
N ≤ 100
이므로 DFS(깊이 우선 탐색)로 충분히 해결 가능.visited[]
) 최적화현재 코드에서는 같은 방을 여러 번 방문하는 경우에도 visited[]
를 계속 변경하지만,
더 많은 골드를 가지고 방문하는 경우도 고려해야 한다.
✅ 해결 방법: visited
배열을 최대 골드 상태를 저장하는 방식
으로 변경하면 불필요한 탐색을 줄일 수 있음.
private static int[] maxMoney;
private static void dfs(int cur, int money) {
if (maxMoney[cur] >= money) return; // 현재 방문한 방의 골드 상태가 더 높으면 탐색 불필요
maxMoney[cur] = money; // 현재 골드 상태 업데이트
...
}
🚀 이렇게 하면 불필요한 재탐색을 줄여 성능을 향상시킬 수 있음.
해당 visited[] 방문처리를 int를 사용해서 진행하는 것이 효율적으로 보여서 진행. 탐색을 진행할때의 탐색지점을 이전에 방문했을때의 돈보다 적거나 같은 경우라면 탐색하지 않는 것으로 진행.
▶ 결과는 메모리초과가 발생, boolean에서 int로 변형한것의 차이가 원인이라고 생각.
visited[]을 int[]형으로 처리하던 중에 문득, a에서 b를 탐색한뒤 다시 a를 되돌아가는 경우가 어떻게되는지 궁금해서 테스트케이스를 진행해봤더니 정확한 답이 도출되지 않았다.
4 E 0 2 0 E 0 3 4 0 L 10 2 0 T 10 2 0 0
해당 테스트케이스를 보면 3번문을 방문한뒤 2번을 다시 방문하고 4번을 가는 경우가 만족되는데 정답코드로 진행하면 false를 도출한다. 추가적인 케이스가 필요해보이고, 게시판에도 언급되어있는 부분이었음.
✅ DFS를 사용하여 모든 경우 탐색
✅ 골드 상태에 따라 이동 가능 여부 결정
✅ visited[]
를 최적화하여 탐색을 줄일 수 있음