Skip to content

Commit

Permalink
Merge branch 'feature/week13'
Browse files Browse the repository at this point in the history
  • Loading branch information
LKHcoding committed Mar 1, 2025
2 parents ad21fb9 + 04c6e36 commit 5e95204
Show file tree
Hide file tree
Showing 148 changed files with 608 additions and 3,637 deletions.
3,637 changes: 0 additions & 3,637 deletions package-lock.json

This file was deleted.

118 changes: 118 additions & 0 deletions src/LKHcoding/jsAlgorithmStudy/week13/49-fatigue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// https://school.programmers.co.kr/learn/courses/30/lessons/87946?language=javascript

function solution(k, dungeons) {
// k는 유저의 현재 피로도
// dungeons는 [최소 필요 피로도, 소모피로도] 가 담긴 2차원 배열

// 방문한 던전을 체크하기 위한 배열
const visited = Array(dungeons.length).fill(false);

// 최대 던전 탐험 횟수
let maxCount = 0;

// DFS로 모든 가능한 던전 순서를 탐색
function dfs(fatigue, count) {
// 현재까지의 탐험 횟수와 최대 탐험 횟수 비교하여 갱신
maxCount = Math.max(maxCount, count);

// 모든 던전을 확인
for (let i = 0; i < dungeons.length; i++) {
const [최소필요피로도, 소모피로도] = dungeons[i];

// 아직 방문하지 않았고, 현재 피로도로 던전 탐험이 가능한 경우
if (!visited[i] && fatigue >= 최소필요피로도) {
visited[i] = true; // 방문 표시

// 던전 탐험 후 피로도 감소시키고 다음 던전으로
dfs(fatigue - 소모피로도, count + 1);

visited[i] = false; // 방문 취소 (백트래킹)
}
}
}

// 초기 피로도와 탐험 횟수 0으로 DFS 시작
dfs(k, 0);

return maxCount;
}

// 테스트 함수
function testSolution() {
const testCases = [
{
k: 80,
dungeons: [
[80, 20],
[50, 40],
[30, 10],
],
expected: 3,
description: '기본 예시 - 문제에서 제공된 테스트 케이스',
},
{
k: 20,
dungeons: [
[80, 20],
[50, 40],
[30, 10],
],
expected: 0,
description: '모든 던전을 돌 수 없는 경우',
},
{
k: 60,
dungeons: [
[80, 20],
[50, 40],
[30, 10],
],
expected: 2,
description: '일부 던전만 돌 수 있는 경우',
},
{
k: 50,
dungeons: [
[30, 10],
[30, 10],
[30, 10],
],
expected: 3,
description: '모든 던전의 최소 필요 피로도가 같은 경우',
},
{
k: 50,
dungeons: [[30, 10]],
expected: 1,
description: '던전이 하나인 경우',
},
{
k: 100,
dungeons: [
[100, 30],
[90, 20],
[80, 40],
[70, 10],
[60, 20],
[50, 5],
],
expected: 4,
description: '더 많은 던전이 있는 복잡한 경우',
},
];

for (let i = 0; i < testCases.length; i++) {
const { k, dungeons, expected, description } = testCases[i];
const result = solution(k, dungeons);
const pass = result === expected;

console.log(`테스트 #${i + 1}: ${description}`);
console.log(` 입력: k=${k}, dungeons=${JSON.stringify(dungeons)}`);
console.log(` 기대 결과: ${expected}, 실제 결과: ${result}`);
console.log(` 테스트 ${pass ? '통과 ✓' : '실패 ✗'}`);
console.log('------------------------');
}
}

// 테스트 실행
testSolution();
205 changes: 205 additions & 0 deletions src/LKHcoding/jsAlgorithmStudy/week13/Summary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
# 49번같은 그래프 문제 스스로 풀기 위한 학습 방법

이해는 했지만 스스로 풀기 어려운 상황은 알고리즘 학습 과정에서 매우 흔한 일이다.
이 DFS와 백트래킹을 활용한 문제를 스스로 풀 수 있도록 단계적인 접근법을 알아보자.

## 1. 문제 유형 파악하기

이 피로도 문제는 **순열(Permutation)** 문제의 응용입니다. 던전을 방문하는 모든 가능한 순서를 탐색하여 최적의 결과를 찾는 문제죠. 이런 유형의 문제는 DFS와 백트래킹 기법으로 해결합니다.

## 2. 사고 과정 단계별로 익히기

문제를 풀 때 다음과 같은 단계로 접근해보세요:

1. **문제 분석**:

- 입력: 현재 피로도(k)와 던전 정보(dungeons)
- 출력: 최대로 탐험할 수 있는 던전 수
- 제약: 던전마다 최소 필요 피로도와, 소모 피로도가 있음

2. **접근법 선택**:

- 던전의 개수가 최대 8개로 적기 때문에 모든 가능한 순서를 탐색해도 됨
- 모든 순서를 시도해봐야 하므로 완전 탐색(DFS/백트래킹) 활용

3. **알고리즘 구조화**:
- 방문 여부를 체크할 배열 필요
- 현재까지의 최대 던전 수를 기록할 변수 필요
- DFS 함수 내에서 모든 던전을 순회하며 방문 가능한 던전을 방문

## 3. 연습을 위한 단계별 접근

### 단계 1: 기본 개념 다지기

먼저 DFS와 백트래킹의 기본 개념을 확실히 이해하세요.

```
DFS 기본 구조:
1. 현재 상태 체크
2. 가능한 모든 선택지에 대해:
- 선택 진행
- 다음 단계 재귀 호출
- 선택 취소(백트래킹)
```

### 단계 2: 쉬운 순열 문제부터 풀어보기

배열 [1,2,3]의 모든 순열을 구하는 간단한 문제로 시작해보세요.

```javascript
function permutation(arr) {
const result = [];
const visited = Array(arr.length).fill(false);
const current = [];

function dfs() {
if (current.length === arr.length) {
result.push([...current]);
return;
}

for (let i = 0; i < arr.length; i++) {
if (!visited[i]) {
visited[i] = true;
current.push(arr[i]);
dfs();
current.pop();
visited[i] = false;
}
}
}

dfs();
return result;
}
```

<details>
<summary>current.pop 설명 보기</summary>

# 순열 백트래킹에서 current.pop()의 역할 설명

`current.pop()`은 백트래킹(backtracking) 알고리즘의 핵심 부분입니다. 이 코드가 하는 일과 그 과정을 단계별로 설명해 드리겠습니다.

## current.pop()의 역할

순열 알고리즘에서 `current.pop()`**이전 상태로 돌아가기 위해** 사용됩니다. 모든 가능한 경로를 탐색한 후, 다른 경로를 시도하기 위해 이전 상태로 되돌리는 역할을 합니다.

## 작동 과정 예시

[1, 2, 3] 배열의 순열을 찾는 과정을 통해 설명해 보겠습니다:

### 1단계: 첫 번째 요소 선택

- `current = []`, `visited = [false, false, false]`
- 요소 1 선택: `current = [1]`, `visited = [true, false, false]`
- `dfs()` 재귀 호출

### 2단계: 두 번째 요소 선택

- 요소 2 선택: `current = [1, 2]`, `visited = [true, true, false]`
- `dfs()` 재귀 호출

### 3단계: 세 번째 요소 선택

- 요소 3 선택: `current = [1, 2, 3]`, `visited = [true, true, true]`
- 조건 충족: `current.length === arr.length`
- 결과에 `[1, 2, 3]` 추가
- 이제 백트래킹 시작!

### 4단계: 첫 번째 백트래킹 (`current.pop()` 실행)

```javascript
current.pop(); // 3을 제거
visited[2] = false; // 3을 미방문 상태로 변경
```

- `current = [1, 2]`, `visited = [true, true, false]`
- 이 재귀 레벨의 for 루프가 종료됨
- 이전 재귀 호출로 돌아감

### 5단계: 두 번째 백트래킹 (`current.pop()` 실행)

```javascript
current.pop(); // 2를 제거
visited[1] = false; // 2를 미방문 상태로 변경
```

- `current = [1]`, `visited = [true, false, false]`
- 다음 요소(3)로 진행

### 6단계: 새로운 경로 탐색

- 요소 3 선택: `current = [1, 3]`, `visited = [true, false, true]`
- `dfs()` 재귀 호출

### 7단계: 남은 요소 선택

- 요소 2 선택: `current = [1, 3, 2]`, `visited = [true, true, true]`
- 결과에 `[1, 3, 2]` 추가
- 다시 백트래킹...

## 시각적 이해

```
[]
/
[1]
/ \
[1,2] [1,3]
| |
[1,2,3] [1,3,2]
pop() pop()
↓ ↓
[1,2] [1,3]
pop() pop()
↓ ↓
[1] [1]
다른 경로 탐색...
```

## 정리

1. `current.pop()`는 현재 탐색 중인 순열에서 마지막 요소를 제거합니다.
2. 이렇게 함으로써 이전 상태로 돌아가서 다른 조합을 시도할 수 있습니다.
3. `visited[i] = false`와 함께 사용되어 방문 표시도 초기화합니다.
4. 이 과정이 없다면 모든 가능한 순열을 생성할 수 없습니다.

이 백트래킹 과정은 "**시도해보고 -> 안되면 되돌아가서 -> 다른 방법 시도**"라는 전략의 구현입니다. 마치 미로에서 길을 찾다가 막다른 길에 도달하면 되돌아가서 다른 경로를 시도하는 것과 같습니다.

---

</details>

### 단계 3: 문제의 단순 버전부터 풀기

피로도 문제를 단순화해서 먼저 풀어보세요. 예를 들어 던전이 2개만 있는 경우부터 시작하여 점점 복잡하게 만들어 보세요.

### 단계 4: 문제를 스스로 다시 풀기

이 문제를 전체 코드를 보지 않고 처음부터 풀어보세요:

1. 함수 틀부터 만들기
2. 필요한 변수(visited, maxCount) 정의
3. DFS 함수의 매개변수(fatigue, count) 정의
4. 중단 조건과 최댓값 갱신 로직 작성
5. 각 던전을 방문하는 로직 작성
6. 백트래킹 구현

## 4. 문제 풀이 연습 전략

1. **패턴 연습**: 유사한 DFS/백트래킹 문제를 여러 개 풀어보세요.
2. **템플릿 만들기**: 자주 사용하는 DFS/백트래킹 패턴을 템플릿화하세요.
3. **시각화**: 재귀 호출의 진행 과정을 그림으로 그려보세요.
4. **문제 변형**: 기존 문제를 살짝 변형해서 스스로 풀어보세요.
5. **설명하기**: 문제 풀이 과정을 다른 사람에게 설명하듯 글로 작성해보세요.

## 5. 추천 연습 문제

이 문제와 유사한 DFS/백트래킹 문제들입니다:

- 프로그래머스: N-Queen, 단어 변환
- 백준: 연산자 끼워넣기(14888), 스타트와 링크(14889)

꾸준히 연습하면 이런 유형의 문제를 스스로 풀 수 있는 능력이 생깁니다. 화이팅하세요! 😊
File renamed without changes.
File renamed without changes.
65 changes: 65 additions & 0 deletions src/corin/week13/49.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// 49. 피로도

//백트래킹을 위한 dfs 함수 생성
function dfs(curk, count, dungeons, visited) {
let answerMax = count;
for (let i = 0; i < dungeons.length; i++) {
// 현재 피로도가 i번째 던전의 최소 필요 피로도보다 크거나 같고,
// i번째 던전을 방문한 적이 없다면
if (curk >= dungeons[i][0] && visited[i] === 0) {
visited[i] = 1;
// 현재까지의 최대 탐험 가능 던전 수와
// i번째 던전에서 이동할 수 있는 최대 탐험 가능 던전 수 중 큰 값을 선택하여 업데이트
// 재귀 호출하면서 다른 모든 경우의 수도 확인
answerMax = Math.max(answerMax, dfs(curk - dungeons[i][1], count + 1, dungeons, visited));
// 백트래킹을 위해 방문 표시를 해제
// 다음 경로 탐색을 위해 현재 던전의 방문 여부를 초기화해야 함
visited[i] = 0;
}
}
return answerMax;
}

function solution(k, dungeons) {
const visited = new Array(dungeons.length).fill(0);
const answerMax = dfs(k, 0, dungeons, visited);
return answerMax;
}


// // -----
// // 1️⃣ 첫 번째 호출
// dfs(80, 0, dungeons, [0,0,0])
// // i = 0 일 때 (첫 번째 던전 선택)
// // 조건: 80 >= 80 && visited[0] === 0 -> true
// visited = [1,0,0]
// ↓
// // 2️⃣ 두 번째 호출
// dfs(60, 1, dungeons, [1,0,0])
// // i = 1 일 때 (두 번째 던전 선택)
// // 조건: 60 >= 50 && visited[1] === 0 -> true
// visited = [1,1,0]
// ↓
// // 3️⃣ 세 번째 호출
// dfs(20, 2, dungeons, [1,1,0])
// // i = 2 일 때 (세 번째 던전 선택)
// // 조건: 20 < 30 -> false
// // 더 이상 진행 불가, count = 2 반환
// ↓
// visited = [1,0,0] (백트래킹)
// // i = 2 일 때 (세 번째 던전 선택)
// // 조건: 60 >= 30 && visited[2] === 0 -> true
// visited = [1,0,1]
// ↓
// // 4️⃣ 네 번째 호출
// dfs(50, 2, dungeons, [1,0,1])
// // i = 1 일 때 (두 번째 던전 선택)
// // 조건: 50 >= 50 && visited[1] === 0 -> true
// visited = [1,1,1]
// ↓
// // 5️⃣ 다섯 번째 호출
// dfs(10, 3, dungeons, [1,1,1])
// // 모든 던전 방문 완료, count = 3 반환
// // 이것이 최대값이 됨!

// // 이후 다른 순서들도 시도하지만 3보다 큰 값은 나오지 않음
Loading

0 comments on commit 5e95204

Please sign in to comment.