diff --git "a/08_\353\260\261\355\212\270\353\236\230\355\202\271/README.md" "b/08_\353\260\261\355\212\270\353\236\230\355\202\271/README.md" index 859845aa..f998fafc 100644 --- "a/08_\353\260\261\355\212\270\353\236\230\355\202\271/README.md" +++ "b/08_\353\260\261\355\212\270\353\236\230\355\202\271/README.md" @@ -22,16 +22,16 @@ | 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | | :-----------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :-------: | :--------------: | -| 20055 | 컨베이어 벨트 위의 로봇 | | [C++]() | 구현, 시뮬레이션 | -| 14888 | 연산자 끼워넣기 | | [C++]() | 백트래킹 | -| 14889 | 스타트와 링크 | | [C++]() | 백트래킹 | +| 20055 | 컨베이어 벨트 위의 로봇 | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/08_%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9/%ED%95%84%EC%88%98/20055.cpp) | 구현, 시뮬레이션 | +| 14888 | 연산자 끼워넣기 | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/08_%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9/%ED%95%84%EC%88%98/14888.cpp) | 백트래킹 | +| 14889 | 스타트와 링크 | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/08_%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9/%ED%95%84%EC%88%98/14889.cpp) | 백트래킹 | ### 도전 | 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | | :--------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :-------: | :------: | -| 프로그래머스 | 소수 찾기 | **Lv.2** | [C++]() | 백트래킹 | -| 2580 | 스도쿠 | | [C++]() | 백트래킹 | +| 프로그래머스 | 소수 찾기 | **Lv.2** | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/08_%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9/%EB%8F%84%EC%A0%84/%EC%86%8C%EC%88%98_%EC%B0%BE%EA%B8%B0.cpp) | 백트래킹 | +| 2580 | 스도쿠 | | [C++_v1](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/08_%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9/%EB%8F%84%EC%A0%84/2580_v1.cpp)
[C++_v2](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/08_%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9/%EB%8F%84%EC%A0%84/2580_v2.cpp) | 백트래킹 | --- diff --git "a/08_\353\260\261\355\212\270\353\236\230\355\202\271/\353\217\204\354\240\204/2580_v1.cpp" "b/08_\353\260\261\355\212\270\353\236\230\355\202\271/\353\217\204\354\240\204/2580_v1.cpp" new file mode 100644 index 00000000..3c7db3bc --- /dev/null +++ "b/08_\353\260\261\355\212\270\353\236\230\355\202\271/\353\217\204\354\240\204/2580_v1.cpp" @@ -0,0 +1,119 @@ +#include +#include + +using namespace std; + +const int MAX = 9; + +bool is_finished; +int sudoku[MAX][MAX]; + +bool checkRow(int r, int n) { + for (int i = 0; i < MAX; i++) { + if (sudoku[r][i] == n) { + return false; + } + } + + return true; +} + +bool checkCol(int c, int n) { + for (int i = 0; i < MAX; i++) { + if (sudoku[i][c] == n) { + return false; + } + } + + return true; +} + +bool checkSquare(int r, int c, int n) { + // (base_r, base_c): (r,c)가 속한 정사각형의 왼쪽 상단 꼭짓점 좌표 + int base_r = r / 3 * 3; + int base_c = c / 3 * 3; + + for (int i = 0; i < (MAX / 3); i++) { + for (int j = 0; j < (MAX / 3); j++) { + if (sudoku[base_r + i][base_c + j] == n) { + return false; + } + } + } + + return true; +} + +bool check(int r, int c, int n) { + return checkRow(r, n) && checkCol(c, n) && checkSquare(r, c, n); +} + +/** + * (0, 0)부터 차례로 빈칸을 채워나간다 + * + * idx: 왼쪽 상단부터 매긴 칸 번호, (row * 9) + col + */ +void fillSudoku(int idx) { + // 재귀 호출 종료 조건: 스도쿠 판을 다 채운 경우 + if (idx == MAX * MAX) { + is_finished = true; + return; + } + + int r = idx / MAX; + int c = idx % MAX; + + // 빈칸이 아닌 경우 + if (sudoku[r][c] != 0) { + // 바로 다음 칸 탐색 + fillSudoku(idx + 1); + } + // 빈칸인 경우 + else { + // i: 이번 빈칸에 넣을 수 + for (int i = 1; i <= MAX; i++) { + // 불가능한 경우 + if (!check(r, c, i)) { + continue; + } + + sudoku[r][c] = i; + fillSudoku(idx + 1); + if (is_finished) { // 채우기에 성공했으면 + return; // 현재 상태를 출력해야 하므로 원상태로 돌려놓지 않고 즉시 종료 + } + sudoku[r][c] = 0; + } + } +} + +/** + * 모든 빈칸에 1~9를 넣어본다. + * 단, 가로, 세로, 정사각형에 같은 수가 있는 경우는 가지치기해준다. + * 가지치기를 위해 가로 9칸, 세로 9칸, 정사각형 9칸을 모두 탐색한다. + * + * 가지치기 시간 복잡도: O(N) + * 약 245ms + */ +int main() +{ + // 입력 + for (int i = 0; i < MAX; i++) { + for (int j = 0; j < MAX; j++) { + cin >> sudoku[i][j]; + } + } + + // 연산 + fillSudoku(0); + + // 출력 + for (int i = 0; i < MAX; i++) { + for (int j = 0; j < MAX; j++) { + cout << sudoku[i][j] << " "; + } + cout << "\n"; + } + + return 0; +} \ No newline at end of file diff --git "a/08_\353\260\261\355\212\270\353\236\230\355\202\271/\353\217\204\354\240\204/2580_v2.cpp" "b/08_\353\260\261\355\212\270\353\236\230\355\202\271/\353\217\204\354\240\204/2580_v2.cpp" new file mode 100644 index 00000000..214930a5 --- /dev/null +++ "b/08_\353\260\261\355\212\270\353\236\230\355\202\271/\353\217\204\354\240\204/2580_v2.cpp" @@ -0,0 +1,112 @@ +#include +#include + +using namespace std; + +const int MAX = 9; + +bool is_finished; +int sudoku[MAX][MAX]; +bool is_in_row[MAX][MAX + 1]; // is_in_row[r][n]: r번 행에 n이 존재하는지 여부 +bool is_in_col[MAX][MAX + 1]; // is_in_col[c][n]: c번 열에 n이 존재하는지 여부 +bool is_in_square[MAX][MAX + 1]; // is_in_square[s][n]: s번 정사각형에 n이 존재하는지 여부 + +/** + * 정사각형 계산 함수 + * (r, c)가 속한 3*3 정사각형의 번호를 리턴 + */ +int calcSquare(int r, int c) { + return (r / 3) * 3 + (c / 3); +} + +void fill(int r, int c, int n) { + sudoku[r][c] = n; + is_in_row[r][n] = true; + is_in_col[c][n] = true; + is_in_square[calcSquare(r, c)][n] = true; +} + +void empty(int r, int c) { + int n = sudoku[r][c]; + sudoku[r][c] = 0; + is_in_row[r][n] = false; + is_in_col[c][n] = false; + is_in_square[calcSquare(r, c)][n] = false; +} + +bool check(int r, int c, int n) { + return !is_in_row[r][n] && !is_in_col[c][n] && !is_in_square[calcSquare(r, c)][n]; +} + +/** + * (0, 0)부터 차례로 빈칸을 채워나간다 + * + * idx: 왼쪽 상단부터 매긴 칸 번호, (row * 9) + col + */ +void fillSudoku(int idx) { + // 재귀 호출 종료 조건: 스도쿠 판을 다 채운 경우 + if (idx == MAX * MAX) { + is_finished = true; + return; + } + + int r = idx / MAX; + int c = idx % MAX; + + // 빈칸이 아닌 경우 + if (sudoku[r][c] != 0) { + // 바로 다음 칸 탐색 + fillSudoku(idx + 1); + } + // 빈칸인 경우 + else { + // i: 이번 빈칸에 넣을 수 + for (int i = 1; i <= MAX; i++) { + // 불가능한 경우 + if (!check(r, c, i)) { + continue; + } + + fill(r, c, i); + fillSudoku(idx + 1); + if (is_finished) { // 채우기에 성공했으면 + return; // 현재 상태를 출력해야 하므로 원상태로 돌려놓지 않고 즉시 종료 + } + empty(r, c); + } + } +} + +/** + * 모든 빈칸에 1~9를 넣어본다. + * 단, 가로, 세로, 정사각형에 같은 수가 있는 경우는 가지치기해준다. + * 가지치기를 위해 각 가로, 세로, 정사각형에 특정 숫자가 존재하는지 여부를 배열로 관리한다. + * + * 가지치기 시간 복잡도: O(1) + * 약 90ms + */ +int main() +{ + int n; + + // 입력 + for (int i = 0; i < MAX; i++) { + for (int j = 0; j < MAX; j++) { + cin >> n; + fill(i, j, n); + } + } + + // 연산 + fillSudoku(0); + + // 출력 + for (int i = 0; i < MAX; i++) { + for (int j = 0; j < MAX; j++) { + cout << sudoku[i][j] << " "; + } + cout << "\n"; + } + + return 0; +} \ No newline at end of file diff --git "a/08_\353\260\261\355\212\270\353\236\230\355\202\271/\353\217\204\354\240\204/\354\206\214\354\210\230_\354\260\276\352\270\260.cpp" "b/08_\353\260\261\355\212\270\353\236\230\355\202\271/\353\217\204\354\240\204/\354\206\214\354\210\230_\354\260\276\352\270\260.cpp" new file mode 100644 index 00000000..7cbe3069 --- /dev/null +++ "b/08_\353\260\261\355\212\270\353\236\230\355\202\271/\353\217\204\354\240\204/\354\206\214\354\210\230_\354\260\276\352\270\260.cpp" @@ -0,0 +1,80 @@ +#include +#include +#include + +using namespace std; + +const int MAX_VAL = 1e8; +const int MAX_N = 7; + +int n; +int answer = 0; +int nums[MAX_N]; +bool is_used[MAX_N]; // is_used[i]: i번 조각을 현재 사용중인지 여부 +bool is_counted[MAX_VAL]; // is_counted[i]: i를 카운트 한 적이 있는지 여부 + +bool isPrime(int x) { + if (x == 0 || x == 1) { + return false; + } + + for (long long i = 2; i * i <= x; i++) { + if (x % i == 0) { + return false; + } + } + + return true; +} + +/** + * 총 N개가 될 때까지 종이 조각을 하나씩 뽑아서 이어붙인다. + * N개를 뽑는 중간 과정에서 만들어지는 수(1 ~ (N-1)개의 조각으로 만든)도 체크해주면서 지나가면, + * 종이 조각들로 만들 수 있는 모든 수를 고려하게 된다. + * + * cnt: 현재까지 뽑은 종이 조각 개수 + * val: 현재까지 뽑은 종이 조각으로 만든 수 + */ +void backtrack(int cnt, int val) { + // 현재까지 만든 수가 소수인지 체크 + // cnt == 0인 경우는 아직 아무것도 뽑지 않았으므로 내가 만든 수가 아님에 유의 + if (cnt > 0 && !is_counted[val] && isPrime(val)) { + answer++; + is_counted[val] = true; + } + + // 재귀 호출 종료 조건: N개를 모두 뽑은 경우 + if (cnt == n) { + return; + } + + // i: 다음으로 뽑을 수 + for (int i = 0; i < n; i++) { + if (is_used[i]) { + continue; + } + + is_used[i] = true; + backtrack(cnt + 1, val * 10 + nums[i]); + is_used[i] = false; + } +} + +int solution(string numbers) { + // 입력 처리 + n = numbers.size(); + for (int i = 0; i < n; i++) { + nums[i] = numbers[i] - '0'; + } + + // 연산 + backtrack(0, 0); + + return answer; +} + +int main() { + cout << solution("17"); + + return 0; +} \ No newline at end of file diff --git "a/08_\353\260\261\355\212\270\353\236\230\355\202\271/\353\217\204\354\240\204/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" "b/08_\353\260\261\355\212\270\353\236\230\355\202\271/\353\217\204\354\240\204/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" deleted file mode 100644 index e69de29b..00000000 diff --git "a/08_\353\260\261\355\212\270\353\236\230\355\202\271/\355\225\204\354\210\230/14888.cpp" "b/08_\353\260\261\355\212\270\353\236\230\355\202\271/\355\225\204\354\210\230/14888.cpp" new file mode 100644 index 00000000..04f275bd --- /dev/null +++ "b/08_\353\260\261\355\212\270\353\236\230\355\202\271/\355\225\204\354\210\230/14888.cpp" @@ -0,0 +1,85 @@ +#include +#include +#include + +using namespace std; + +const int INF = 1e9; +const int MAX_N = 11; +const int ADD = 0, SUB = 1, MUL = 2, DIV = 3; +const int EXP_NUM = 4; + +int n; +int nums[MAX_N]; +int expression[EXP_NUM]; +int max_val = -INF, min_val = INF; + +/** + * 연산자를 하나씩, 총 (N-1)개가 될 때까지 뽑는다. + * + * cnt: 뽑은 연산자의 개수 + * curr_val: 현재 연산값 + */ +void backtrack(int cnt, int curr_val) { + // 재귀 호출 종료 조건: (N-1)개의 연산자를 다 뽑은 경우 + if (cnt == n - 1) { + max_val = max(max_val, curr_val); + min_val = min(min_val, curr_val); + return; + } + + // i: 연산자 번호 + for (int i = 0; i < EXP_NUM; i++) { + // 사용할 연산자가 남아있지 않으면, 사용 불가 + if (expression[i] == 0) { + continue; + } + + // 연산자 사용 + expression[i]--; + int new_sum = 0; + switch (i) { + case ADD: + new_sum = curr_val + nums[cnt + 1]; + break; + case SUB: + new_sum = curr_val - nums[cnt + 1]; + break; + case MUL: + new_sum = curr_val * nums[cnt + 1]; + break; + case DIV: + new_sum = curr_val / nums[cnt + 1]; + break; + } + + // 다음 연산자 선택 + backtrack(cnt + 1, new_sum); + + // 연산자 반납 + expression[i]++; + } +} + +/** + * 모든 연산자 조합을 시도해보면서 최대값과 최솟값을 찾는다. + * 모든 연산자 조합을 만들기 위해 가장 왼쪽에 들어갈 연산자부터 하나씩 선택한다. + */ +int main() { + // 입력 + cin >> n; + for (int i = 0; i < n; i++) { + cin >> nums[i]; + } + for (int i = 0; i < EXP_NUM; i++) { + cin >> expression[i]; + } + + // 연산 + backtrack(0, nums[0]); + + // 출력 + cout << max_val << '\n' << min_val; + + return 0; +} \ No newline at end of file diff --git "a/08_\353\260\261\355\212\270\353\236\230\355\202\271/\355\225\204\354\210\230/14889.cpp" "b/08_\353\260\261\355\212\270\353\236\230\355\202\271/\355\225\204\354\210\230/14889.cpp" new file mode 100644 index 00000000..539ad283 --- /dev/null +++ "b/08_\353\260\261\355\212\270\353\236\230\355\202\271/\355\225\204\354\210\230/14889.cpp" @@ -0,0 +1,85 @@ +#include +#include +#include + +using namespace std; + +const int MAX_N = 20; +const int INF = 1e9; + +int n; +int min_power_gap = INF; +int s[MAX_N][MAX_N]; +bool is_start[MAX_N]; + +int calcTeamPowerGap() { + int start_power = 0; + int link_power = 0; + + for (int i = 0; i < n - 1; i++) { + for (int j = i + 1; j < n; j++) { + int ssum = s[i][j] + s[j][i]; + + // i와 j 모두 스타트 팀인 경우 + if (is_start[i] && is_start[j]) { + start_power += ssum; + } + // i와 j 모두 링크 팀인 경우 + else if (!is_start[i] && !is_start[j]) { + link_power += ssum; + } + } + } + + return abs(start_power - link_power); +} + +/** + * 스타트팀원을 한명씩 뽑는다. + * 중복 탐색을 막기 위해 팀원의 번호가 오름차순이 되도록 뽑는다. + * ex) [1, 2]와 [2, 1]은 같은 케이스 이므로 [1, 2]만 탐색 + * + * idx: 남은 사람들 중 가장 빠른 번호 + * cnt: 현재까지 뽑은 사람 수 + */ +void backtrack(int idx, int cnt) { + // 재귀 호출 종료 조건: n/2명을 다 뽑은 경우 + if (cnt == (n / 2)) { + int power_gap = calcTeamPowerGap(); + min_power_gap = min(min_power_gap, power_gap); + return; + } + + // [idx+1, idx+2, ..., n-1] 중에서 다음 팀원을 뽑음 + for (int i = idx; i < n; i++) { + is_start[i] = true; + backtrack(i + 1, cnt + 1); + is_start[i] = false; + } +} + +/** + * 스타트: [1, 2], 링크: [0, 3]인 경우와 + * 스타트: [0, 3], 링크: [1, 2]인 경우는 같다. + * 특정 사람이 있는 팀 / 없는 팀으로만 구별하면 된다. + * 0번이 있는 팀과 없는 팀으로 구별하자. 그리고 0번이 있는 팀을 스타트팀이라고 부르자. + * 스타트팀을 뽑는 모든 조합을 전부 시도해본다. + */ +int main() { + // 입력 + cin >> n; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + cin >> s[i][j]; + } + } + + // 연산 + is_start[0] = true; + backtrack(1, 1); + + // 출력 + cout << min_power_gap << '\n'; + + return 0; +} diff --git "a/08_\353\260\261\355\212\270\353\236\230\355\202\271/\355\225\204\354\210\230/20055.cpp" "b/08_\353\260\261\355\212\270\353\236\230\355\202\271/\355\225\204\354\210\230/20055.cpp" new file mode 100644 index 00000000..15c9f153 --- /dev/null +++ "b/08_\353\260\261\355\212\270\353\236\230\355\202\271/\355\225\204\354\210\230/20055.cpp" @@ -0,0 +1,106 @@ +#include +#include + +using namespace std; + +struct info { // 내구도와 로봇 존재 여부 + int power; + bool is_on; +}; + +/* 벨트를 한 칸 회전*/ +void rotateBelt(deque &belt, int n) { + belt.push_front(belt.back()); + belt.pop_back(); + belt[n - 1].is_on = false; // 로봇이 내리는 위치 +} + +/* 로봇을 움직일 수 있으면 한 칸 이동*/ +void moveRobot(deque &belt, int n) { + for (int i = n - 2; i >= 0; i--) { // 배열 접근 가능 범위가 0 ~ n-1 인데 다음 칸과 비교해야 하니까 0 ~ n-2 + if (belt[i].is_on && (!belt[i + 1].is_on) && (belt[i + 1].power >= 1)) { + // 지금 칸에 로봇이 존재하고, 다음 칸에 로봇이 없으며, 다음 칸에 내구도가 남아있을 때 + belt[i].is_on = false; + belt[i + 1].is_on = true; + belt[i + 1].power--; + } + belt[n - 1].is_on = false; // 로봇이 내리는 위치 + } +} + +/* 올리는 칸에 로봇을 올릴 수 있으면 올림 */ +void putRobot(deque &belt) { + if (!belt[0].is_on && belt[0].power >= 1) { + // 올리는 칸에 로봇이 존재하지 않고, 내구도가 남아있으면 + belt[0].is_on = true; + belt[0].power--; + } +} + +/* 벨트의 내구도 체크 */ +bool checkFinish(deque &belt, int n, int k) { + int count = 0; + for (int i = 0; i < 2 * n; i++) { + if (belt[i].power == 0) { + count++; + } + } + + if (count >= k) { + return true; + } + return false; +} + +int solution(deque &belt, int n, int k) { + int step = 1; + while (true) { + // 회전 + rotateBelt(belt, n); + // 이동 + moveRobot(belt, n); + // 로봇 올리기 + putRobot(belt); + + // 내구도 체크하기 + if (checkFinish(belt, n, k)) { + return step; + } + step++; + } +} + + +/** + * [컨베이어 벨트 위의 로봇 문제] + * 1. 벨트가 각 칸 위의 로봇과 함께 한 칸 회전 + * 2. 가장 먼저 벨트에 올라간 로봇부터, 벨트 회전 방향으로 한 칸 이동할 수 있다면 이동 + * (이동가능: 이동하려는 칸에 로봇이 없고, 그 칸의 내구도가 1 이상이어야 함) + * 3. 올리는 위치에 있는 칸의 내구도가 0이 아니면 올리는 위치에 로봇 올림 + * 4. 내구도가 0인 칸의 개수가 k개 이상이라면 과정 종료. 그렇지 않다면 1로 돌아감 + * -> 1 ~ 3까지가 1단계 + * + * [문제 풀이] + * 회전과 관련이 깊은 자료구조 deque를 사용하여 풀이 + * + * 1번 벨트 회전: 벨트의 마지막 원소를 벨트 처음에 넣기 + * 2번 로봇 이동: 가장 먼저 올라간 로봇부터 고려해야 하므로 (내리는 위치 - 1)부터 (올리는 위치)까지 검사 + * -> 로봇 옮기는거 가능하면 존재여부 체크하고 내구도 감소 + * 3번 로봇 추가: 올리는 위치 칸 내구도 0이 아니라면 해당 칸 로봇 존재 여부 체크 + 내구도 감소 + * + * + * >> 주의: 칸 번호를 1번이 아닌 0번부터 시작하는 것으로 관리하고 있기 때문에, n번 칸이 아니라 n-1번 칸이 내리는 위치 << + */ + +int main() { + // 입력 + int n, k; + cin >> n >> k; + deque belt(2 * n); // 컨베이어 벨트의 내구도와 로봇 존재 여부 저장 + for (int i = 0; i < 2 * n; i++) { + cin >> belt[i].power; + belt[i].is_on = false; + } + // 연산 & 출력 + cout << solution(belt, n, k); +} \ No newline at end of file diff --git "a/08_\353\260\261\355\212\270\353\236\230\355\202\271/\355\225\204\354\210\230/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" "b/08_\353\260\261\355\212\270\353\236\230\355\202\271/\355\225\204\354\210\230/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" deleted file mode 100644 index e69de29b..00000000 diff --git "a/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/README.md" "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/README.md" index e69de29b..00305430 100644 --- "a/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/README.md" +++ "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/README.md" @@ -0,0 +1,76 @@ +# 동적 계획법 (Dynamic Programming) + +[메인으로 돌아가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4) + +## 💻 튜터링 + +### 라이브 코딩 + +| 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | +| :-----------------------------------------------------------------------: | :----------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :----------: | :--------: | +| 2579 | 계단 오르기 | | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/09_%EB%8F%99%EC%A0%81%20%EA%B3%84%ED%9A%8D%EB%B2%95/%EB%9D%BC%EC%9D%B4%EB%B8%8C%20%EC%BD%94%EB%94%A9/2579.cpp) | DP | +| 12865 | 평범한 배낭 | | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/09_%EB%8F%99%EC%A0%81%20%EA%B3%84%ED%9A%8D%EB%B2%95/%EB%9D%BC%EC%9D%B4%EB%B8%8C%20%EC%BD%94%EB%94%A9/12865.cpp) | DP | +| 11660 | 구간 합 구하기 5 | | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/09_%EB%8F%99%EC%A0%81%20%EA%B3%84%ED%9A%8D%EB%B2%95/%EB%9D%BC%EC%9D%B4%EB%B8%8C%20%EC%BD%94%EB%94%A9/11660.cpp) | DP, 누적합 | + +## ✏️ 과제 + +### 마감기한 + +~ 5 / 1 (월) 23:59 - 과제 제출
+~ 5 / 4 (목) 23:59 - 추가 제출
+ +### 필수 + +| 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | +| :-----------------------------------------------------------------------: | :------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :-------: | :------------------------: | +| 20923 | 숫자 할리갈리 게임 | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/09_%EB%8F%99%EC%A0%81%20%EA%B3%84%ED%9A%8D%EB%B2%95/%ED%95%84%EC%88%98/20923.cpp) | 구현, 시뮬레이션, 자료구조 | +| 11726 | 2xn 타일링 | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/09_%EB%8F%99%EC%A0%81%20%EA%B3%84%ED%9A%8D%EB%B2%95/%ED%95%84%EC%88%98/11726.cpp) | DP | +| 1149 | RGB거리 | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/09_%EB%8F%99%EC%A0%81%20%EA%B3%84%ED%9A%8D%EB%B2%95/%ED%95%84%EC%88%98/1149.cpp) | DP | + +### 도전 + +| 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | +| :--------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :-------: | :--: | +| 프로그래머스 | 가장 큰 정사각형 찾기 | **Lv.2** | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/09_%EB%8F%99%EC%A0%81%20%EA%B3%84%ED%9A%8D%EB%B2%95/%EB%8F%84%EC%A0%84/%EA%B0%80%EC%9E%A5_%ED%81%B0_%EC%A0%95%EC%82%AC%EA%B0%81%ED%98%95.cpp) | DP | +| 9084 | 동전 | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/09_%EB%8F%99%EC%A0%81%20%EA%B3%84%ED%9A%8D%EB%B2%95/%EB%8F%84%EC%A0%84/9048.cpp) | DP | + +--- + +### 힌트 + +
+숫자 할리갈리 게임 +
+    카드를 어떤 자료구조로 관리하면 좋을까요? 게임을 반복해서 진행하네요. 함수화를 통해 효율적으로 코드를 작성할 수 있을 것 같아요! 덱이 비어있는 경우에 주의하세요! +
+
+ +
+2xn 타일링 +
+    가장 마지막 세로줄을 채울 수 있는 방법이 총 몇 가지 있나요? +
+
+ +
+RGB거리 +
+    1차원 DP 배열로 해결이 가능할까요? +
+
+ +
+가장 큰 정사각형 찾기 +
+    라이브 코딩의 11660번 문제 접근법을 복습해보아요. +
+
+ +
+동전 +
+    라이브 코딩의 계단 문제와 비슷한 느낌이 들지 않나요? 점화식을 잘 세워보면 쉽게 풀릴 것 같아요. +
+
+ +--- diff --git "a/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\352\260\225\354\235\230 \354\236\220\353\243\214/09_\353\217\231\354\240\201\352\263\204\355\232\215\353\262\225_\353\254\270\354\240\234\355\225\264\354\204\244.pdf" "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\352\260\225\354\235\230 \354\236\220\353\243\214/09_\353\217\231\354\240\201\352\263\204\355\232\215\353\262\225_\353\254\270\354\240\234\355\225\264\354\204\244.pdf" new file mode 100644 index 00000000..b60caa0c Binary files /dev/null and "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\352\260\225\354\235\230 \354\236\220\353\243\214/09_\353\217\231\354\240\201\352\263\204\355\232\215\353\262\225_\353\254\270\354\240\234\355\225\264\354\204\244.pdf" differ diff --git "a/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\352\260\225\354\235\230 \354\236\220\353\243\214/09_\353\217\231\354\240\201\352\263\204\355\232\215\353\262\225_\354\235\264\353\241\240.pdf" "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\352\260\225\354\235\230 \354\236\220\353\243\214/09_\353\217\231\354\240\201\352\263\204\355\232\215\353\262\225_\354\235\264\353\241\240.pdf" new file mode 100644 index 00000000..7c791730 Binary files /dev/null and "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\352\260\225\354\235\230 \354\236\220\353\243\214/09_\353\217\231\354\240\201\352\263\204\355\232\215\353\262\225_\354\235\264\353\241\240.pdf" differ diff --git "a/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\352\260\225\354\235\230 \354\236\220\353\243\214/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\352\260\225\354\235\230 \354\236\220\353\243\214/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" deleted file mode 100644 index e69de29b..00000000 diff --git "a/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\353\217\204\354\240\204/9048.cpp" "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\353\217\204\354\240\204/9048.cpp" new file mode 100644 index 00000000..1c5c9ab4 --- /dev/null +++ "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\353\217\204\354\240\204/9048.cpp" @@ -0,0 +1,57 @@ +#include +#include + +using namespace std; + +int countNumberOfCases(int n, int m, vector& coins) { + // dp[i]: i원을 만드는 경우의 수 + vector dp(m + 1, 0); + + // 0원을 만드는 경우의 수는 1가지 + dp[0] = 1; + + // i: 고려하고 있는 동전 번호 + // j: 목표 금액 + for (int i = 0; i < n; i++) { + for (int j = coins[i]; j <= m; j++) { + // i번 동전을 사용하지 않으면, 남은 금액 j를 만들어야 함 + // i번 동전 하나를 사용하면, 남은 금액 (j - coins[i])을 만들어야 함 + dp[j] = dp[j] + dp[j - coins[i]]; + } + } + + return dp[m]; +} + +/** + * dp[i] = 주어진 동전 종류를 사용해서 i원을 만드는 경우의 수 + * + * dp[0] = 1 을 넣고 시작 (0원을 만드는 경우의 수 1로 생각) + * 각 동전마다 해당 동전부터 만들어야 하는 금액(m)까지 돌리면서 해당 동전을 사용하기 전 금액의 경우의 수와 현재 경우의 수를 더함 + * 해당 동전 사용하기 전 금액의 경우의 수가 0이면 금액을 만들 수 없는 경우이지만, 어차피 더해도 값 변화는 없으므로 따로 고려하지 않음 + */ + +int main() { + int t; + + cin >> t; + while (t--) { + int n, m; + + // 입력 + cin >> n; + vector coins(n); + for (int i = 0; i < n; i++) { + cin >> coins[i]; + } + cin >> m; + + // 연산 + int answer = countNumberOfCases(n, m, coins); + + // 출력 + cout << answer << "\n"; + } + + return 0; +} \ No newline at end of file diff --git "a/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\353\217\204\354\240\204/\352\260\200\354\236\245_\355\201\260_\354\240\225\354\202\254\352\260\201\355\230\225.cpp" "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\353\217\204\354\240\204/\352\260\200\354\236\245_\355\201\260_\354\240\225\354\202\254\352\260\201\355\230\225.cpp" new file mode 100644 index 00000000..ea7ba713 --- /dev/null +++ "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\353\217\204\354\240\204/\352\260\200\354\236\245_\355\201\260_\354\240\225\354\202\254\352\260\201\355\230\225.cpp" @@ -0,0 +1,64 @@ +#include +#include +#include + +using namespace std; + +int maxSquare(int row, int col, vector>& board) { + // dp[i][j]: (i, j)를 우측하단 꼭짓점으로 하는 가장 큰 정사각형의 한 변의 길이 + vector> dp(row + 1, vector(col + 1, 0)); + int ret = 0; + + for (int i = 1; i <= row; i++) { + for (int j = 1; j <= col; j++) { + // 꼭짓점이 0인 경우, 정사각형의 크기는 0 + if (board[i - 1][j - 1] == 0) { + continue; + } + + // 북서쪽(↖) 정사각형, 북쪽(↑) 정사각형, 서쪽(←) 정사각형으로 쪼갤 수 있음, + // 그 중 가장 작은 정사각형의 한 변의 길이 X에 맞춰 자른 뒤 + // (i, j)를 꼭짓점으로 한 칸 추가하면 한 변의 길이가 (X+1)인 정사각형이 됨 + dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1; + ret = max(ret, dp[i][j]); // 최대값 갱신 + } + } + + return ret * ret; +} + +/** + * 정사각형은 다음과 같이 쪼갤 수 있음 + * ex. 4x4 정사각형 + * = (↖ 3x3 정사각형) + (↑ 3x3 정사각형) + (← 3x3 정사각형) + (오른쪽 아래 1x1 정사각형) + * + * 1 1 1 1 1 1 1 0 0 1 1 1 0 0 0 0 0 0 0 0 + * 1 1 1 1 = 1 1 1 0 + 0 1 1 1 + 1 1 1 0 + 0 0 0 0 + * 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 0 0 0 0 0 + * 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 + * + * 따라서 dp[i][j]: (i, j)를 우측하단 꼭짓점으로 하는 가장 큰 정사각형의 한 변의 길이 라고 하면 + * dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]} + 1 + */ +int solution(vector> board) +{ + int row = board.size(); + int col = board[0].size(); + + int answer = maxSquare(row, col, board); + + return answer; +} + +int main() { + vector> board = + { + {0, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 1, 1}, + {0, 0, 1, 0} + }; + cout << solution(board); + + return 0; +} \ No newline at end of file diff --git "a/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\353\217\204\354\240\204/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\353\217\204\354\240\204/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" deleted file mode 100644 index e69de29b..00000000 diff --git "a/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/11660.cpp" "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/11660.cpp" new file mode 100644 index 00000000..0b978685 --- /dev/null +++ "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/11660.cpp" @@ -0,0 +1,55 @@ +#include +#include +#include + +using namespace std; + +void calcPsum(int n, vector>& A, vector>& psum) { + // psum[i][j]: (1,1)부터 (i,j)까지의 합 + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= n; j++) { + psum[i][j] = psum[i - 1][j] + psum[i][j - 1] - psum[i - 1][j - 1] + A[i][j]; + } + } +} + +int calcSum(int x1, int y1, int x2, int y2, vector>& psum) { + return psum[x2][y2] - psum[x2][y1 - 1] - psum[x1 - 1][y2] + psum[x1 - 1][y1 - 1]; +} + +int main() { + // 빠른 입출력 + ios_base::sync_with_stdio(); + cin.tie(NULL); cout.tie(NULL); + + int n, m; + + // 입력: 데이터 + cin >> n >> m; + vector> A(n + 1, vector(n + 1, 0)); + vector> psum(n + 1, vector(n + 1, 0)); + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= n; j++) { + cin >> A[i][j]; + } + } + + // 연산: 누적합 테이블 구해두기 + calcPsum(n, A, psum); + + // 쿼리 + for (int i = 0; i < m; i++) { + int x1, y1, x2, y2; + + // 입력 + cin >> x1 >> y1 >> x2 >> y2; + + // 연산 + int answer = calcSum(x1, y1, x2, y2, psum); + + // 출력 + cout << answer << "\n"; + } + + return 0; +} \ No newline at end of file diff --git "a/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/12865.cpp" "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/12865.cpp" new file mode 100644 index 00000000..4bb1d4b8 --- /dev/null +++ "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/12865.cpp" @@ -0,0 +1,69 @@ +#include +#include + +using namespace std; + +// 1차원 DP 배열 사용 +int knapsack1(int n, int k, vector& w, vector& v) { + // dp[i]: 준서가 버틸 수 있는 무게가 i일 때, 물건들을 넣어 얻을 수 있는 가치합의 최대값 + vector dp(k + 1, 0); + + // i: 현재 넣으려는 물건 + // j: 버틸 수 있는 무게 + for (int i = 1; i <= n; i++) { + for (int j = k; j >= w[i]; j--) { + // 물건을 넣는 경우 vs. 넣지 않는 경우 + int packing = dp[j - w[i]] + v[i]; + int not_packing = dp[j]; + dp[j] = max(packing, not_packing); + } + } + + return dp[k]; +} + +// 2차원 DP 배열 사용 +int knapsack2(int n, int k, vector& w, vector& v) { + // dp[i][j]: 준서가 버틸 수 있는 무게가 j일 때, 1~i번 물건들을 넣어 얻을 수 있는 가치합의 최대값 + vector> dp(n + 1, vector(k + 1, 0)); + + // i: 현재 넣으려는 물건 + // j: 버틸 수 있는 무게 + for (int i = 1; i <= n; i++) { + // 버틸 수 있는 무게 < 물건 무게 + for (int j = 0; j < w[i]; j++) { + // 무조건 넣지 못함 + dp[i][j] = dp[i - 1][j]; + } + + // 버틸 수 있는 무게 >= 물건 무게 + for (int j = w[i]; j <= k; j++) { + // 물건을 넣는 경우 vs. 넣지 않는 경우 + int packing = dp[i - 1][j - w[i]] + v[i]; + int not_packing = dp[i - 1][j]; + dp[i][j] = max(packing, not_packing); + } + } + + return dp[n][k]; +} + +int main() { + int n, k; + + // 입력 + cin >> n >> k; + vector w(n + 1); + vector v(n + 1); + for (int i = 1; i <= n; i++) { + cin >> w[i] >> v[i]; + } + + // 연산 + int answer = knapsack1(n, k, w, v); + + // 출력 + cout << answer; + + return 0; +} \ No newline at end of file diff --git "a/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/2579.cpp" "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/2579.cpp" new file mode 100644 index 00000000..e533262c --- /dev/null +++ "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/2579.cpp" @@ -0,0 +1,41 @@ +#include +#include + +using namespace std; + +int maxScore(int n, vector &score) { + // dp[i]: i번째 계단에 도착했을 때 점수의 최대값 + vector dp(n + 1, 0); + + // 두 번째 계단까지는 모든 칸을 밟고 오는 것이 최대 + dp[1] = score[1]; + dp[2] = score[1] + score[2]; + + for (int i = 3; i <= n; i++) { + // 한 칸 전에서 온 경우 vs. 두 칸 전에서 온 경우 + int one_step_before = dp[i - 3] + score[i - 1]; // 세 칸을 연속으로 밟을 수 없으므로 + int two_steps_before = dp[i - 2]; + dp[i] = max(one_step_before, two_steps_before) + score[i]; + } + + return dp[n]; +} + +int main() { + int n; + + // 입력 + cin >> n; + vector score(n + 1, 0); + for (int i = 1; i <= n; i++) { + cin >> score[i]; + } + + // 연산 + int answer = maxScore(n, score); + + // 출력 + cout << answer; + + return 0; +} \ No newline at end of file diff --git "a/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" deleted file mode 100644 index e69de29b..00000000 diff --git "a/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\355\225\204\354\210\230/1149.cpp" "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\355\225\204\354\210\230/1149.cpp" new file mode 100644 index 00000000..28d6e481 --- /dev/null +++ "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\355\225\204\354\210\230/1149.cpp" @@ -0,0 +1,45 @@ +#include +#include +#include + +using namespace std; + +const int R = 0, G = 1, B = 2; + +int paint(int n, vector>& houses) { + // dp[i][j]: i번째 집은 j색으로 칠할 때, 1~i번 집까지 칠하는 최소 비용 + vector> dp(n + 1, vector(3, 0)); + + for (int i = 1; i <= n; i++) { + // (i-1)번 집은 남은 두 색상 중 하나로 칠해야 함 + dp[i][R] = min(dp[i - 1][G], dp[i - 1][B]) + houses[i][R]; + dp[i][G] = min(dp[i - 1][B], dp[i - 1][R]) + houses[i][G]; + dp[i][B] = min(dp[i - 1][R], dp[i - 1][G]) + houses[i][B]; + } + + return min({dp[n][R], dp[n][G], dp[n][B]}); +} + +/** + * 1번집 부터 차례로 색칠합니다. + * 만약 i번 집을 빨간색으로 칠한다면, (i-1)번 집을 초록색이나 파란색으로 칠했어야 합니다. + * 초록색과 파란색 중 더 비용이 적게 드는 색을 선택하면 됩니다. + */ +int main() { + int n; + + // 입력 + cin >> n; + vector> houses(n + 1, vector(3, 0)); + for (int i = 1; i <= n; i++) { + cin >> houses[i][R] >> houses[i][G] >> houses[i][B]; + } + + // 연산 + int answer = paint(n, houses); + + // 출력 + cout << answer; + + return 0; +} \ No newline at end of file diff --git "a/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\355\225\204\354\210\230/11726.cpp" "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\355\225\204\354\210\230/11726.cpp" new file mode 100644 index 00000000..ea797065 --- /dev/null +++ "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\355\225\204\354\210\230/11726.cpp" @@ -0,0 +1,47 @@ +#include +#include + +using namespace std; + +int countNumberOfCases(int n) { + const int MOD = 10'007; + // dp[i]: 2xi 크기의 직사각형을 채우는 방법의 수 + vector dp(n+1); + + dp[1] = 1; // 세로로 한 개만 + dp[2] = 2; // 세로로 두 개 or 가로로 두 개 + + for (int i = 3; i <= n; i++) { + int vertical = dp[i - 1]; // 세로로 한 개 놓는 경우 + int horizontal = dp[i - 2]; // 가로로 두 개 놓는 경우 + dp[i] = (vertical + horizontal) % MOD; // 오버플로우 방지를 위해 MOD 연산 + } + + return dp[n]; +} + +/** + * 가장 마지막 세로줄을 채울 수 있는 방법을 살펴봅시다. + * 1. 세로로 한 개를 놓는다. + * 2. 가로로 두 개를 놓는다. + * + * 1번 방법으로 마지막 세로줄을 채울 경우, 남은 부분의 크기는 2 x (n-1) + * 2번 방법으로 마지막 세로줄을 채울 경우, 남은 부분의 크기는 2 x (n-2) + * + * 따라서 2 x n 크기의 직사각형을 채우는 방법의 수는 + * d[i] = dp[i - 1] + dp[i - 2] + */ +int main() { + int n; + + // 입력 + cin >> n; + + // 연산 + int answer = countNumberOfCases(n); + + // 출력 + cout << answer; + + return 0; +} \ No newline at end of file diff --git "a/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\355\225\204\354\210\230/20923.cpp" "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\355\225\204\354\210\230/20923.cpp" new file mode 100644 index 00000000..99a26c27 --- /dev/null +++ "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\355\225\204\354\210\230/20923.cpp" @@ -0,0 +1,94 @@ +#include +#include +#include + +using namespace std; + +typedef vector> cards; +const int DO = 0, SU = 1; + +// 승리 판단하기 +string judge(cards& deck) +{ + int do_deck = deck[DO].size(), su_deck = deck[SU].size(); + if (do_deck > su_deck) { + return "do"; + } + else if (do_deck < su_deck) { + return "su"; + } + return "dosu"; +} + +// 그라운드에서 덱으로 카드 옮기기 +void groundToDeck(deque& deck, deque& ground) { + while (!ground.empty()) { + deck.push_back(ground.back()); + ground.pop_back(); + } +} + +// 종을 쳤을 때 +void ringTheBell(int player, cards& deck, cards& ground) { + groundToDeck(deck[player], ground[!player]); // 카드 가져가기 (상대 그라운드 -> 본인 덱) + groundToDeck(deck[player], ground[player]); // 카드 가져가기 (본인 그라운드 -> 본인 덱) +} + + +// 종을 울릴 수 있는 사람 판단 +int whoCanRingTheBell(cards& deck, cards& ground) { + if (!ground[DO].empty() && ground[DO].front() == 5) { // 도도 + return DO; + } + else if (!ground[SU].empty() && ground[SU].front() == 5) { // 도도 + return DO; + } + else if (!ground[DO].empty() && !ground[SU].empty() && (ground[DO].front() + ground[SU].front() == 5)) { // 수연 + return SU; + } + return -1; // 종을 울릴 수 없음 +} + +// 게임 진행 +string game(int m, cards& deck, cards& ground) { + bool turn = DO; // 도도 먼저 + while (m--) + { + ground[turn].push_front(deck[turn].front()); // 카드 내려놓기(덱 -> 그라운드) + deck[turn].pop_front(); + if (deck[turn].empty()) { + break; + } + int bell = whoCanRingTheBell(deck, ground); // 종을 울릴 수 있는 사람 + if (bell != -1) { // 종을 울린 경우 + ringTheBell(bell, deck, ground); + } + turn = !turn; // 차례 바꾸기 + } + return judge(deck); +} + +/* +* 도도, 수연이 각각 덱과 그라운드를 가짐 +* 도도->수연->도도->수연... 순으로 차례를 바꿔가며 게임 진행 (game 함수) +* 1. 카드를 덱에서 한 장 내려놓음 +* 2. 어떤 플레이어가 종을 칠 수 있는지 판단 (whoCanRingTheBell 함수) +* 3. 종을 친 경우 그라운드의 카드를 덱으로 이동(ringTheBell, groundToDeck 함수) +* 종료 조건 만족 시 승리한 사람 리턴(judge 함수) +*/ + +int main() +{ + int n, m, card1, card2; + cards deck(2), ground(2); // 0: 도도, 1: 수연 + // 입력 + cin >> n >> m; + while (n--) { + cin >> card1 >> card2; + deck[DO].push_front(card1); + deck[SU].push_front(card2); + } + // 출력 & 연산 + cout << game(m, deck, ground) << '\n'; + return 0; +} \ No newline at end of file diff --git "a/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\355\225\204\354\210\230/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" "b/09_\353\217\231\354\240\201 \352\263\204\355\232\215\353\262\225/\355\225\204\354\210\230/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" deleted file mode 100644 index e69de29b..00000000 diff --git "a/10_\354\235\264\353\266\204 \355\203\220\354\203\211/README.md" "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/README.md" index e69de29b..0fc99b42 100644 --- "a/10_\354\235\264\353\266\204 \355\203\220\354\203\211/README.md" +++ "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/README.md" @@ -0,0 +1,77 @@ +# 이분 탐색 (Binary Search) + +[메인으로 돌아가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4) + +## 💻 튜터링 + +### 라이브 코딩 + +| 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | +| :-----------------------------------------------------------------------: | :----------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :----------: | :--------: | +| 1920 | 수 찾기 | | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/10_%EC%9D%B4%EB%B6%84%20%ED%83%90%EC%83%89/%EB%9D%BC%EC%9D%B4%EB%B8%8C%20%EC%BD%94%EB%94%A9/1920.cpp) | 이분탐색, 정렬 | +| 10816 | 숫자 카드 2 | | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/10_%EC%9D%B4%EB%B6%84%20%ED%83%90%EC%83%89/%EB%9D%BC%EC%9D%B4%EB%B8%8C%20%EC%BD%94%EB%94%A9/10816.cpp) | 이분탐색, 정렬, 해시를 이용한 집합과 맵 | +| 2110 | 공유기 설치 | | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/10_%EC%9D%B4%EB%B6%84%20%ED%83%90%EC%83%89/%EB%9D%BC%EC%9D%B4%EB%B8%8C%20%EC%BD%94%EB%94%A9/2110.cpp) | 이분 탐색, 매개 변수 탐색 | + +## ✏️ 과제 + +### 마감기한 + +~ 5 / 9 (화) 18:59 - 과제 제출
+~ 5 / 11 (목) 23:59 - 추가 제출
+ +### 필수 + +| 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | +| :-----------------------------------------------------------------------: | :------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :-------: | :------------------------: | +| 14500 | 테트로미노 | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/10_%EC%9D%B4%EB%B6%84%20%ED%83%90%EC%83%89/%ED%95%84%EC%88%98/14500.cpp) | 구현, 브루트 포스 | +| 10815 | 숫자 카드 | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/10_%EC%9D%B4%EB%B6%84%20%ED%83%90%EC%83%89/%ED%95%84%EC%88%98/10815.cpp) | 자료구조, 정렬, 이분 탐색 | +| 16401 | 과자 나눠주기 | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/10_%EC%9D%B4%EB%B6%84%20%ED%83%90%EC%83%89/%ED%95%84%EC%88%98/16401.cpp) | 이분 탐색, 매개 변수 탐색 | + +### 도전 + +| 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | +| :--------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :-------: | :--: | +| 2343 | 기타 레슨 | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/10_%EC%9D%B4%EB%B6%84%20%ED%83%90%EC%83%89/%EB%8F%84%EC%A0%84/2343.cpp) | 이분 탐색, 매개 변수 탐색 | +| 3079 | 입국심사 | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/10_%EC%9D%B4%EB%B6%84%20%ED%83%90%EC%83%89/%EB%8F%84%EC%A0%84/3079.cpp) | 이분 탐색, 매개 변수 탐색 | + +--- + +### 힌트 + +
+테트로미노 +
+    테트로미노의 모양은 탐색의 관점에서 특징이 있는 것 같아요! +
+
+ +
+숫자 카드 +
+    라이브 코딩 문제를 복습하며 풀어봅시다. 찾아야 할 게 무엇일까요? +
+
+ +
+과자 나눠주기 +
+    막대 과자는 길이와 상관없이 여러 조각으로 나눠질 수 있어요! +
+
+ +
+기타 레슨 +
+    블루레이 크기의 범위는 무엇일까요? +
+
+ +
+입국심사 +
+    라이브 코딩 때 풀어본 공유기 설치 문제와 유사해보이네요. 어떤 값을 기준으로 탐색하여 무엇을 비교해야 할지 생각해보세요 :) +자료형의 범위에 유의해주세요 +
+
+ +--- diff --git "a/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\352\260\225\354\235\230 \354\236\220\353\243\214/10_\354\235\264\353\266\204\355\203\220\354\203\211_\353\254\270\354\240\234\355\225\264\354\204\244.pdf" "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\352\260\225\354\235\230 \354\236\220\353\243\214/10_\354\235\264\353\266\204\355\203\220\354\203\211_\353\254\270\354\240\234\355\225\264\354\204\244.pdf" new file mode 100644 index 00000000..cfb78cc5 Binary files /dev/null and "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\352\260\225\354\235\230 \354\236\220\353\243\214/10_\354\235\264\353\266\204\355\203\220\354\203\211_\353\254\270\354\240\234\355\225\264\354\204\244.pdf" differ diff --git "a/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\352\260\225\354\235\230 \354\236\220\353\243\214/10_\354\235\264\353\266\204\355\203\220\354\203\211_\354\235\264\353\241\240.pdf" "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\352\260\225\354\235\230 \354\236\220\353\243\214/10_\354\235\264\353\266\204\355\203\220\354\203\211_\354\235\264\353\241\240.pdf" new file mode 100644 index 00000000..43bc9ded Binary files /dev/null and "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\352\260\225\354\235\230 \354\236\220\353\243\214/10_\354\235\264\353\266\204\355\203\220\354\203\211_\354\235\264\353\241\240.pdf" differ diff --git "a/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\352\260\225\354\235\230 \354\236\220\353\243\214/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\352\260\225\354\235\230 \354\236\220\353\243\214/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" deleted file mode 100644 index e69de29b..00000000 diff --git "a/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\353\217\204\354\240\204/2343.cpp" "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\353\217\204\354\240\204/2343.cpp" new file mode 100644 index 00000000..6f55f40b --- /dev/null +++ "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\353\217\204\354\240\204/2343.cpp" @@ -0,0 +1,50 @@ +#include +#include +#include + +using namespace std; + +/* +* 적절한 블루레이의 크기를 매개변수 탐색을 이용해 찾습니다. +* 이 때, 각 블루레이의 크기는 최대 강의 길이(maxLen) 이상, 강의 길이의 합(sumLen) 이하임을 이용합니다. +*/ + +int findSize(int&left, int right, vector lesson, int n, int m) { + // 적절한 블루레이의 크기를 이진탐색을 이용해 찾기 + while (left <= right) { + int mid = (left + right) / 2; // mid(찾는 값): 블루레이 크기 후보 + int count = 0; // 블루레이의 개수 + int sum_blue = 0; // 각 블루레이의 크기 + + for (int i = 0; i < n; i++) { + if (sum_blue + lesson[i] > mid) { + count++; + sum_blue = 0; + } + sum_blue += lesson[i]; + } + count++; + // 사이즈가 mid일 때의 블루레이 개수가 m보다 작거나 같으면 더 작은 사이즈로 가정하고 탐색 + // 반대의 경우, 더 큰 값으로 가정하고 대해 탐색 + (count <= m) ? right = mid - 1 : left = mid + 1; + } + return left; +} + +int main() { + int n, m, sum_len = 0, max_len = 0; + // 강의의 수, 블루레이의 수 입력 + cin >> n >> m; + + // 강의 동영상 길이 입력받을 벡터 + vector lesson(n); + // 강의 동영상의 길이 입력 + for (int i = 0; i < n; i++) { + cin >> lesson[i]; + sum_len += lesson[i]; // 강의 길이의 합 갱신 + max_len = max(lesson[i], max_len); // 강의 길이의 최댓값 갱신 + } + // 연산 & 출력 + cout << findSize(max_len, sum_len, lesson, n, m); + return 0; +} \ No newline at end of file diff --git "a/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\353\217\204\354\240\204/3079.cpp" "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\353\217\204\354\240\204/3079.cpp" new file mode 100644 index 00000000..8923f205 --- /dev/null +++ "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\353\217\204\354\240\204/3079.cpp" @@ -0,0 +1,64 @@ +#include +#include +#include + +using namespace std; + +typedef long long ll; +const int MAX = 1e5; + +/* +* 매개변수 탐색을 이용하여 입국 심사에 걸리는 시간을 계산합니다. +* 각 입국 심사에 걸리는 시간에 따라 심사가능한 인원을 계산한 후, 일행 인원과 비교해가며 진행합니다. +*/ + +ll paramSearch(ll &m, ll &n, vector& times, ll &max_wait) { + // 최소 시간: 0, 최대 대기 시간: 최대 단일 대기시간*m + ll left = 0, right = max_wait*m; + // 대기 시간의 최댓값으로 설정 후 값을 줄여갑니다 + ll result = right; + + while (left <= right) { + ll mid = (left + right) / 2; + ll sum = 0; // mid만큼 기다릴 때, 입국심사 가능한 인원 + for (int i = 0; i < n; i++) { + sum += mid / times[i]; + if (sum > m){ + break; + } + } + // 입국심사 가능한 인원이 일행 수보다 크거나 같은 경우 -> 더 적게 기다릴 수도 있음 + if (sum >= m) { + result = min(result, mid); + right = mid - 1; + } + // 입국심사 가능한 인원이 일행 수보다 작은 경우 -> 더 오래 기다려야 함 + else { + left = mid + 1; + } + } + return result; +} + +int main(void) { + ios_base::sync_with_stdio(0); + cin.tie(0); cout.tie(0); + + ll n, m; + ll max_wait = -1; + vector times(MAX+1); + + // 입력 + cin >> n >> m; + + // 입국심사에 걸리는 시간 입력 + for (int i = 0; i < n; i++) { + cin >> times[i]; + max_wait = max(max_wait, times[i]); + } + sort(times.begin(), times.begin()+n); + + // 연산 & 출력 + cout << paramSearch(m, n, times, max_wait); + return 0; +} \ No newline at end of file diff --git "a/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\353\217\204\354\240\204/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\353\217\204\354\240\204/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" deleted file mode 100644 index e69de29b..00000000 diff --git "a/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/10816.cpp" "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/10816.cpp" new file mode 100644 index 00000000..cd8029ab --- /dev/null +++ "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/10816.cpp" @@ -0,0 +1,79 @@ +#include +#include +#include + +using namespace std; +/* +* lower bound, upper bound를 구한 뒤, 둘의 차이를 구해주면 됩니다. +*/ + +//lower bound +int lowerBound(int left, int right, int target, vector& arr) { + while (left <= right) { + int mid = (left + right) / 2; + // 중간값이 target보다 크다면 target은 왼쪽에 있음 + // 중간값이 target과 같다면 왼쪽에 target과 같은 값이 더 있을 수 있음 + if (arr[mid] >= target) { + right = mid - 1; + } + else { // 중간값이 target보다 작다면 target은 오른쪽에 있음 + left = mid + 1; + } + } + /* + * left를 리턴하는 이유 + * break 조건: left 포인터가 right 포인터보다 뒤에 있는 경우 + * arr[mid] <= target일 때, left 포인터가 이동하고 break + * 이 때 left값은 target이 되는 첫 지점 즉 lower bound임 + */ + return left; +} + +//upper bound +int upperBound(int left, int right, int target, vector& arr) { + while (left <= right) { + int mid = (left + right) / 2; + // 중간값이 target보다 작다면 target은 오른쪽에 있음 + // 중간값이 target과 같다면 오른쪽에 target과 같은 값이 더 있을 수 있음 + if (arr[mid] <= target) { + left = mid + 1; + } + else { // 중간값이 target보다 크다면 target은 왼쪽에 있음 + right = mid - 1; + } + } + /** + * left를 리턴하는 이유 + * break 조건: left 포인터가 right 포인터보다 뒤에 있는 경우 + * arr[mid] == target 일 때 left가 target을 초과하는 순간 break + * 이 때의 left 값이 upper bound + */ + return left; +} + +int main() { + ios_base::sync_with_stdio(false); + cin.tie(NULL); + cout.tie(NULL); + + int n, m, input; + + //입력 + cin >> n; + vector arr(n, 0); + for (int i = 0; i < n; i++) { + cin >> arr[i]; + } + + //이분 탐색을 하기 위해 정렬 + sort(arr.begin(), arr.end()); + + //입력 + cin >> m; + while (m--) { + cin >> input; + //연산 & 출력 + cout << upperBound(0, n - 1, input, arr) - lowerBound(0, n - 1, input, arr) << ' '; + } + return 0; +} \ No newline at end of file diff --git "a/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/1920.cpp" "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/1920.cpp" new file mode 100644 index 00000000..8c76ea77 --- /dev/null +++ "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/1920.cpp" @@ -0,0 +1,51 @@ +#include +#include +#include +#include + +using namespace std; +/* +* 이분탐색을 이용해 입력으로 주어진 키 값의 존재 여부를 구합니다 +*/ + +int binarySearch(int n, int key, vector &nums) { + int left = 0; + int right = n - 1; + int mid; + // 키 값의 존재여부 구하기 + while (left <= right) { + mid = (left + right) / 2; + if (nums[mid] == key) { // key 값이 배열의 중앙값과 같을 때 + return 1; + } + else if (nums[mid] > key) { // key 값이 배열의 중앙값보다 작을 때-> 더 작은 값 탐색 + right = mid - 1; + } + else { // key 값이 배열의 중앙값보다 클때-> 더 큰 값 탐색 + left = mid + 1; + } + } + return 0; +} + +int main(void) { + cin.tie(0); cout.tie(0); + ios_base::sync_with_stdio(NULL); + + int n, m, key; + // 입력 + cin >> n; + vector nums(n); // 자연수의 최대 개수가 100000이므로 해당 크기의 배열을 만들기 + for (int i = 0; i < n; i++) { + cin >> nums[i]; + } + sort(nums.begin(), nums.end()); // quick sort를 이용해 배열 오름차순으로 정렬 + // 입력 + cin >> m; + while(m--) { + cin >> key; + // 연산 & 출력 + cout << binarySearch(n, key, nums) << '\n'; + } + return 0; +} diff --git "a/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/2110.cpp" "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/2110.cpp" new file mode 100644 index 00000000..4a22d19a --- /dev/null +++ "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/2110.cpp" @@ -0,0 +1,57 @@ +#include +#include +#include + +using namespace std; + +// 가장 인접한 두 공유기 사이의 거리가 dist가 되도록 공유기를 설치했을 때, 설치된 공유기 개수 +int cntRouter(int dist, vector& router) { + // 첫번째 집에 무조건 공유기 설치 + int cnt = 1; + int cur = router[0]; + + for (int i = 1; i < router.size(); i++) { + if (router[i] - cur >= dist) { // 가장 가까운 집과의 거리가 dist 이상이라면 + cnt++; // 공유기 설치 + cur = router[i]; + } + } + return cnt; // 설치된 공유기의 수 +} + +// 최소 인접 거리 중 최댓값 구하기 +int binarySearch(int left, int right, int target, vector& router) { + while (left <= right) { + // 가장 인접한 두 공유기 사이의 거리가 mid일 때, 설치할 수 있는 공유기 개수 + int mid = (left + right) / 2; + int installed = cntRouter(mid, router); + + if (installed >= target) { // mid의 거리로는 target 개수 이상의 공유기를 설치할 수 있음 -> 거리를 늘려보자 + left = mid + 1; + } + else { // mid의 거리로는 target만큼의 공유기 설치할 수 없음 -> 거리를 줄여야 한다 + right = mid - 1; + } + } + return left - 1; //upper bound값에서 1을 뺌 +} + +int main() { + int n, c; + + // 입력 + cin >> n >> c; + vector house(n, 0); + for (int i = 0; i < n; i++) { + cin >> house[i]; + } + + // 연산 + sort(house.begin(), house.end()); + + // 연산 & 출력 + // 최소 거리: 1 + // 최장 거리: 가장 멀리 떨어진 두 집 사이의 거리 + cout << binarySearch(1, house[n - 1] - house[0], c, house); + return 0; +} \ No newline at end of file diff --git "a/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" deleted file mode 100644 index e69de29b..00000000 diff --git "a/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\355\225\204\354\210\230/10815.cpp" "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\355\225\204\354\210\230/10815.cpp" new file mode 100644 index 00000000..ecb19094 --- /dev/null +++ "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\355\225\204\354\210\230/10815.cpp" @@ -0,0 +1,46 @@ +#include +#include +#include + +using namespace std; + +/* +* 카드의 존재 여부만 판단하면 되므로, 이분 탐색을 이용해 해당 카드의 인덱스를 찾습니다. +*/ + +int binarySearch(int num, vector& card, int n) { + //카드 인덱스의 최소값: 0, 최대값: n + int left = 0; int right = n; + while (left <= right) { + int mid = (left + right) / 2; + if (num == card[mid]) { + return 1; + } + if (num > card[mid]) { + left = mid + 1; + } + else right = mid - 1; + } + return 0; +} + + +int main() { + ios_base::sync_with_stdio(0); + cin.tie(0); cout.tie(0); + // 입력 + int n, m, num; + cin >> n; + vector card(n); + for (int i = 0; i < n; i++) { + cin >> card[i]; + } + sort(card.begin(), card.end()); // 이분 탐색을 위해 정렬 + + cin >> m; + while (m--) { + cin >> num; + // 연산 & 출력 + cout << binarySearch(num, card, n) << ' '; + } +} \ No newline at end of file diff --git "a/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\355\225\204\354\210\230/14500.cpp" "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\355\225\204\354\210\230/14500.cpp" new file mode 100644 index 00000000..f0ed47ec --- /dev/null +++ "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\355\225\204\354\210\230/14500.cpp" @@ -0,0 +1,85 @@ +#include +#include +#include + +using namespace std; + +vector>board; + +int ans; + +void dfs(int x, int y, int depth, int sum) { + + vector dx = { -1,0,1,0 }; + vector dy = { 0,1,0,-1 }; + + if (depth == 4) { // 칸 4개 선택했으면 ans 최대값 갱신 + ans = max(ans, sum); + return; + } + + // 아래 코드가 들어가면 가지치기가 돼 백트래킹이 돼요! + //if (ans >= MAX * (4 - cnt) + sum) { + // return; + //} + + for (int i = 0; i < 4; i++) { + // 선택할 칸 + int nx = x + dx[i]; + int ny = y + dy[i]; + + if (nx < 0 || nx >= board.size() || ny < 0 || ny >= board[0].size() || !board[nx][ny]) { // 범위를 벗어났거나 이미 방문한 블록이라면 넘어가기 + continue; + } + + int temp = board[nx][ny]; // 방문 처리하기 전 해당 칸 가치 저장 + board[nx][ny] = 0; // 방문 처리 : 4개를 선택함에 있어서 똑같은 블록을 선택하지 않기 위해 + + // 다음 탐색 -> depth 1 증가 && sum값에 현재 칸 가치 더하기 + if (depth == 2) { // ㅜ 모양은 현재 위치에서 다시 탐색! + dfs(x, y, depth + 1, sum + temp); + } + dfs(nx, ny, depth + 1, sum + temp); // 선택한 칸으로 이동 + + board[nx][ny] = temp; // 이후의 케이스에서 재방문할 수 있으므로 원래대로 돌려줌 + + } +} + +/* +* HINT : 하나의 도형은 무언가 특별한 것 같아요! or 테트로미노의 모양은 탐색의 관점에서 특징이 있는 것 같아요! +* 1. ㅜ 모양을 제외한 테트로미노의 모양은 깊이가 4인 dfs의 탐색 모양 +* -> dfs로 블록을 하나씩 선택해가면서 개수(cnt)와 합(sum)을 계산 +* -> 4개 선택하면 최댓값 갱신 +* 2. 예외 : ㅜ 모양은 블록을 2개 선택했을 때 현재 블록에서 다시 블록을 선택해준다. +*/ + + +int main() { + + // 입력 + int n, m; + cin >> n >> m; + board.assign(n, vector(m, 0)); + + + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + cin >> board[i][j]; + } + } + + // 연산 + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + int temp = board[i][j]; + board[i][j] = 0; + dfs(i, j, 1, temp); + board[i][j] = temp; + } + } + + // 출력 + cout << ans; + return 0; +} \ No newline at end of file diff --git "a/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\355\225\204\354\210\230/16401.cpp" "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\355\225\204\354\210\230/16401.cpp" new file mode 100644 index 00000000..6002a61d --- /dev/null +++ "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\355\225\204\354\210\230/16401.cpp" @@ -0,0 +1,47 @@ +#include +#include + +using namespace std; + +/* +* 이분 탐색을 이용하여 나눠줄 수 있는 최대한 긴 과자의 길이를 찾아낸다. +*/ + +#define MAX_COOKIE 1000000000 + +int binarySearch(int m, vector &cookie) { + int right = MAX_COOKIE; // 과자의 최대 길이: 1000000000 + int left = 1; // 과자의 최소 길이: 1 + int res=0; + + while (left <= right) { + int mid = (left + right) / 2; + int cnt = 0; + // mid 길이만큼씩 나눠주면 몇 명에게 나눠줄 수 있는지 세기 + for (int i = 0; i < cookie.size(); i++) { + cnt += cookie[i] / mid; + } + if (cnt >= m) { + left = mid + 1; + res = mid; + } + else{ + right = mid - 1; + } + } + return res; +} + +int main() { + int m, n; + // 조카 수, 과자 수 입력 + cin >> m >> n; + vector cookie(n); + // 막대과자 길이 입력 + for (int i = 0; i < n; i++) { + cin >> cookie[i]; + } + // 연산 & 출력 + cout << binarySearch(m, cookie); + return 0; +} \ No newline at end of file diff --git "a/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\355\225\204\354\210\230/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" "b/10_\354\235\264\353\266\204 \355\203\220\354\203\211/\355\225\204\354\210\230/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" deleted file mode 100644 index e69de29b..00000000 diff --git "a/11_\355\210\254 \355\217\254\354\235\270\355\204\260/README.md" "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/README.md" index e69de29b..043b423e 100644 --- "a/11_\355\210\254 \355\217\254\354\235\270\355\204\260/README.md" +++ "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/README.md" @@ -0,0 +1,76 @@ +# 투 포인터 (Two Pointer) + +[메인으로 돌아가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4) + +## 💻 튜터링 + +### 라이브 코딩 + +| 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | +| :-----------------------------------------------------------------------: | :----------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :----------: | :--------: | +| 11659 | 구간 합 구하기4 | | [바로가기]() | 누적 합 | +| 21921 | 블로그 | | [바로가기]() | 누적 합, 슬라이딩 윈도우 | +| 2470 | 두 용액 | | [바로가기]() | 투 포인터 | + +## ✏️ 과제 + +### 마감기한 + +~ 5 / 16 (화) 18:59 - 과제 제출
+~ 5 / 18 (목) 23:59 - 추가 제출
+ +### 필수 + +| 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | +| :-----------------------------------------------------------------------: | :------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :-------: | :------------------------: | +| 14503 | 로봇 청소기 | | [C++]() | 구현, 시뮬레이션 | +| 20922 | 겹치는 건 싫어 | | [C++]() | 투 포인터 | +| 20437 | 문자열 게임 2 | | [C++]() | 슬라이딩 윈도우 | + +### 도전 + +| 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | +| :--------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :-------: | :--: | +| 13422 | 도둑 | | [C++]() | 투 포인터, 슬라이딩 윈도우 | +| 2473 | 세 용액 | | [C++]() | 투 포인터 | +--- + +### 힌트 + +
+로봇 청소기 +
+    청소할 공간이 없을 때까지 계속해서 청소하는 방식이네요. 배웠던 알고리즘과 비슷해보이지 않나요? 방향에 유의하여 풀어보아요. +
+
+ +
+겹치는 건 싫어 +
+    두 포인터를 맨 왼쪽에 두고 오른쪽에 있는 숫자를 현재 수열에 추가할 수 있을지 없을지를 생각하며 탐색해볼까요? +
+
+ +
+문자열 게임 2 +
+    특정 문자가 k개 포함되면서 양쪽 끝이 해당 문자로 같아야 한다고 하니 우리에게 필요한 건 각 문자의 위치겠네요! 슬라이딩 윈도우를 사용해서 풀이해줘야 할 것 같은데, 윈도우의 크기는 얼마여야 할까요? +
+
+ +
+도둑 +
+    마을이 원이라는 점에 주의하여 슬라이딩 윈도우로 훔칠 수 있는 돈을 계산해봅시다. +
+
+ +
+세 용액 +
+    라이브코딩에서 다뤘던 두 용액 문제에 용액 하나가 추가됐네요! 포인터 3개를 쓰기는 힘들 것 같으니 결국 투포인터를 사용해 풀이해줘야 하는데, 나머지 하나는 어떻게 하면 좋을까요? 한 용액이 반드시 포함되도록 하고 나머지 두 용액을 찾아주면 좋을 것 같네요. +
+
+ + +--- diff --git "a/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\352\260\225\354\235\230 \354\236\220\353\243\214/11_\355\210\254\355\217\254\354\235\270\355\204\260_\353\254\270\354\240\234\355\225\264\354\204\244.pdf" "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\352\260\225\354\235\230 \354\236\220\353\243\214/11_\355\210\254\355\217\254\354\235\270\355\204\260_\353\254\270\354\240\234\355\225\264\354\204\244.pdf" new file mode 100644 index 00000000..793aa5cb Binary files /dev/null and "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\352\260\225\354\235\230 \354\236\220\353\243\214/11_\355\210\254\355\217\254\354\235\270\355\204\260_\353\254\270\354\240\234\355\225\264\354\204\244.pdf" differ diff --git "a/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\352\260\225\354\235\230 \354\236\220\353\243\214/11_\355\210\254\355\217\254\354\235\270\355\204\260_\354\235\264\353\241\240.pdf" "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\352\260\225\354\235\230 \354\236\220\353\243\214/11_\355\210\254\355\217\254\354\235\270\355\204\260_\354\235\264\353\241\240.pdf" new file mode 100644 index 00000000..dfd988c8 Binary files /dev/null and "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\352\260\225\354\235\230 \354\236\220\353\243\214/11_\355\210\254\355\217\254\354\235\270\355\204\260_\354\235\264\353\241\240.pdf" differ diff --git "a/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\352\260\225\354\235\230 \354\236\220\353\243\214/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\352\260\225\354\235\230 \354\236\220\353\243\214/\355\214\214\354\235\274\354\227\205\353\241\234\353\223\234\354\232\251" deleted file mode 100644 index e69de29b..00000000 diff --git "a/12_\355\212\270\353\246\254/\355\225\204\354\210\230/15681.cpp" "b/12_\355\212\270\353\246\254/\355\225\204\354\210\230/15681.cpp" new file mode 100644 index 00000000..5193489f --- /dev/null +++ "b/12_\355\212\270\353\246\254/\355\225\204\354\210\230/15681.cpp" @@ -0,0 +1,51 @@ +// 15681 트리와 쿼리 +/* + DP + DFS +*/ +#include +#include +#include + +using namespace std; + +int dfs(int sub_root, vector>& adj, vector& vis, vector& dp) { + + if (!dp[sub_root]) { + return dp[sub_root]; + } + vis[sub_root] = true; + int num = 1; // 자기 자신은 무조건 포함하므로 1로 초기화 후 시작합니다 + //다음 탐색 + for (auto nxt : adj[sub_root]) { + if (vis[nxt]) { + continue; + } + num += dfs(nxt, adj, vis, dp); + } + return dp[sub_root]; +} + +int main() { + ios_base::sync_with_stdio(false); + cin.tie(NULL); + cout.tie(NULL); + + int N, R, Q; + int x, y; + int sub_root; + cin >> N >> R >> Q; + vector> adj(N + 1, vector(0)); // 연결리스트 저장방법 + vector vis(N + 1, false); // 방문 표시 배열 초기화 + vector dp(N + 1, 0); + for (int i = 0; i < N - 1; i++) { + cin >> x >> y; + adj[x].push_back(y); + adj[y].push_back(x); + } + dp[R] = dfs(R, adj, vis, dp); + while (Q--) { + cin >> sub_root; + cout << dp[sub_root] << "\n"; + } + return 0; +} \ No newline at end of file diff --git "a/12_\355\212\270\353\246\254/\355\225\204\354\210\230/5639.cpp" "b/12_\355\212\270\353\246\254/\355\225\204\354\210\230/5639.cpp" new file mode 100644 index 00000000..c8d369b9 --- /dev/null +++ "b/12_\355\212\270\353\246\254/\355\225\204\354\210\230/5639.cpp" @@ -0,0 +1,62 @@ +// 5639 이진 검색 트리 +#include +#include + +using namespace std; +typedef pair ci; +map tree; // key, value + +void preOrder(char c) +{ + if(c == '.') + { + return; + } + cout << c; + preOrder(tree[c].first); + preOrder(tree[c].second); +} + + + +void inOrder(char c) { + if (c == '.') { + return; + } + + inOrder(tree[c].first); + cout << c; + inOrder(tree[c].second); +} + +// 후위 순회 +void postOrder(char c) { + if (c == '.') { + return; + } + + postOrder(tree[c].first); + postOrder(tree[c].second); + cout << c; +} + + + +int main(){ + int N; + char root, left, right; + + cin >> N; + while(N--) + { + cin >> root >> left >> right; + tree[root]= make_pair(left, right); + } + + preOrder('A'); + cout << "\n"; + inOrder('A'); + cout << "\n"; + postOrder('A'); + cout << "\n"; +} \ No newline at end of file diff --git "a/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\355\225\204\354\210\230/1238.cpp" "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\355\225\204\354\210\230/1238.cpp" new file mode 100644 index 00000000..61605407 --- /dev/null +++ "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\355\225\204\354\210\230/1238.cpp" @@ -0,0 +1,67 @@ +// 1238 파티 +// 다익스트라 알고리즘 +/* +문제 해석: +(1번 학생 집-> 파티장소)+(파티장소->1번 학생 집) vs ... vs(i번째 학생 집->파티장소)+(파티장소->i번째 학생 집) 거리 중 최댓값을 구하는 것 +파티장소를 출발점으로 다익스트라 돌리고(step1), 뒤집은 그래프로도 출발점을 돌리면 (step2)--> step1+step2=complete +*/ +#include +#include +#include + +using namespace std; +typedef pair pi; +const int INF = 1e5; + +vector dijkstra(int start, int N, vector> &adj) { + vector dist(N + 1, INF); //dist 배열을 INF로 초기화 + priority_queue, greater> pq; // pq 선언 + + dist[start] = 0; + pq.push({0, start}); + + while (!pq.empty()) { + int cur_cost = pq.top().first; // 현재까지의 cost값 + int cur = pq.top().second; // cur := 현재 정점 + pq.pop(); + + if (cur_cost > dist[cur]) { //이미 더 작은 값으로 기록된 정점이 있다면 + continue; + } + for (int i = 0; i < adj[cur].size(); i++) { // 현재 값과 연결된 모든 정점들을 탐색해본다. + int nxt = adj[cur][i].first; + int nxt_cost = cur_cost + adj[cur][i].second; + if (nxt_cost < dist[nxt]) { + dist[nxt] = nxt_cost; + pq.push({nxt_cost, nxt}); + } + } + } + return dist; +} + +int main() +{ + ios_base::sync_with_stdio(false); + cin.tie(NULL), cout.tie(NULL); + + int N, M, X, a, b, c; + cin >> N >> M >> X; + vector> adj(N + 1, vector(0)); + while(M--){ + cin >> a >> b >> c; + adj[a].push_back({b,c}); + } + + vector vr1 = dijkstra(X, N, adj); + + int ans = 0; + for (int i = 1; i <= N; i++) { + vector vr2 = dijkstra(i, N, adj); // i 부터 X의의 최단 시간 + ans = max(ans, vr1[i] + vr2[X]); + } + + cout << ans << "\n"; + + return 0; +} \ No newline at end of file diff --git "a/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\355\225\204\354\210\230/2458..cpp" "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\355\225\204\354\210\230/2458..cpp" new file mode 100644 index 00000000..00e15fa5 --- /dev/null +++ "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\355\225\204\354\210\230/2458..cpp" @@ -0,0 +1,49 @@ +// 2458 +// 플로이드-워셜 알고리즘 이용 + +#include +#include +#include + +using namespace std; +const int CONNECT = 1; + +void floydWarShall(int N, vector> &adj){ + for(int i = 1; i <= N; i++){ + for(int j = 1; j <= N; j++){ + for(int k = 1; k <= N; k++){ + if(adj[j][i] && adj[i][k]) { + adj[j][k] = CONNECT; + } + } + } + } +} + +int main(){ + ios_base::sync_with_stdio(false); cin.tie(0); + int N, M, x, y; + cin >> N >> M; + vector> adj(N+1, vector(N+1, 0)); + while(M--){ + cin >> x >> y; + adj[x][y] = CONNECT; + } + floydWarShall(N, adj); + // 답 얻어내기 + int answer = 0; + for(int i = 1; i <= N; i++){ + int connected_student = 0; + for(int j = 1; j <= N; j++) { + if(adj[i][j] == CONNECT || adj[j][i] == CONNECT) { + connected_student++; // 자신을 제외한 N-1명 학생이 연결돼있나? + + if(connected_student >= N-1) { // N-1명 이상이 연결되어있음 + answer++; + } + } + } + } + cout << answer << "\n"; + +} \ No newline at end of file diff --git a/15681.cpp b/15681.cpp new file mode 100644 index 00000000..5193489f --- /dev/null +++ b/15681.cpp @@ -0,0 +1,51 @@ +// 15681 트리와 쿼리 +/* + DP + DFS +*/ +#include +#include +#include + +using namespace std; + +int dfs(int sub_root, vector>& adj, vector& vis, vector& dp) { + + if (!dp[sub_root]) { + return dp[sub_root]; + } + vis[sub_root] = true; + int num = 1; // 자기 자신은 무조건 포함하므로 1로 초기화 후 시작합니다 + //다음 탐색 + for (auto nxt : adj[sub_root]) { + if (vis[nxt]) { + continue; + } + num += dfs(nxt, adj, vis, dp); + } + return dp[sub_root]; +} + +int main() { + ios_base::sync_with_stdio(false); + cin.tie(NULL); + cout.tie(NULL); + + int N, R, Q; + int x, y; + int sub_root; + cin >> N >> R >> Q; + vector> adj(N + 1, vector(0)); // 연결리스트 저장방법 + vector vis(N + 1, false); // 방문 표시 배열 초기화 + vector dp(N + 1, 0); + for (int i = 0; i < N - 1; i++) { + cin >> x >> y; + adj[x].push_back(y); + adj[y].push_back(x); + } + dp[R] = dfs(R, adj, vis, dp); + while (Q--) { + cin >> sub_root; + cout << dp[sub_root] << "\n"; + } + return 0; +} \ No newline at end of file diff --git a/5639.cpp b/5639.cpp new file mode 100644 index 00000000..c8d369b9 --- /dev/null +++ b/5639.cpp @@ -0,0 +1,62 @@ +// 5639 이진 검색 트리 +#include +#include + +using namespace std; +typedef pair ci; +map tree; // key, value + +void preOrder(char c) +{ + if(c == '.') + { + return; + } + cout << c; + preOrder(tree[c].first); + preOrder(tree[c].second); +} + + + +void inOrder(char c) { + if (c == '.') { + return; + } + + inOrder(tree[c].first); + cout << c; + inOrder(tree[c].second); +} + +// 후위 순회 +void postOrder(char c) { + if (c == '.') { + return; + } + + postOrder(tree[c].first); + postOrder(tree[c].second); + cout << c; +} + + + +int main(){ + int N; + char root, left, right; + + cin >> N; + while(N--) + { + cin >> root >> left >> right; + tree[root]= make_pair(left, right); + } + + preOrder('A'); + cout << "\n"; + inOrder('A'); + cout << "\n"; + postOrder('A'); + cout << "\n"; +} \ No newline at end of file diff --git a/README.md b/README.md index 841ca8e8..dbf4b4d4 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,9 @@ SW학부 원스탑 튜터링에서 진행하는 코딩 테스트 대비 알고 | 2023.03.24 | 그리디 알고리즘 | [@grdnr13](https://github.com/grdnr13) | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/06_%EA%B7%B8%EB%A6%AC%EB%94%94%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98/%EA%B0%95%EC%9D%98%20%EC%9E%90%EB%A3%8C/06_%EA%B7%B8%EB%A6%AC%EB%94%94%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98_%EC%9D%B4%EB%A1%A0.pdf) | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/tree/main/06_%EA%B7%B8%EB%A6%AC%EB%94%94%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98) | - | | 2023.03.31 | DFS & BFS | [@kimyu0218](https://github.com/kimyu0218) | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/07_DFS%20%26%20BFS/%EA%B0%95%EC%9D%98%20%EC%9E%90%EB%A3%8C/07_DFS%26BFS_%EC%9D%B4%EB%A1%A0.pdf) | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/tree/main/07_DFS%20%26%20BFS) | - | | 2023.04.07 | 백트래킹 | [@sujeong000](https://github.com/sujeong000) | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/08_%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9/%EA%B0%95%EC%9D%98%20%EC%9E%90%EB%A3%8C/08_%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9_%EC%9D%B4%EB%A1%A0.pdf) | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/tree/main/08_%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9) | - | -| 2023.04.14 | 동적 계획법 | [@sujeong000](https://github.com/sujeong000) | [바로가기]() | [바로가기]() | - | -| 2023.05.05 | 이분 탐색 | [@grdnr13](https://github.com/grdnr13) | [바로가기]() | [바로가기]() | 녹화 강의 제공 | -| 2023.05.12 | 투 포인터 | [@kwakrhkr59](https://github.com/kwakrhkr59) | [바로가기]() | [바로가기]() | - | +| 2023.04.14 | 동적 계획법 | [@sujeong000](https://github.com/sujeong000) | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/09_%EB%8F%99%EC%A0%81%20%EA%B3%84%ED%9A%8D%EB%B2%95/%EA%B0%95%EC%9D%98%20%EC%9E%90%EB%A3%8C/09_%EB%8F%99%EC%A0%81%EA%B3%84%ED%9A%8D%EB%B2%95_%EC%9D%B4%EB%A1%A0.pdf) | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/tree/main/09_%EB%8F%99%EC%A0%81%20%EA%B3%84%ED%9A%8D%EB%B2%95) | - | +| 2023.05.05 | 이분 탐색 | [@grdnr13](https://github.com/grdnr13) | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/10_%EC%9D%B4%EB%B6%84%20%ED%83%90%EC%83%89/%EA%B0%95%EC%9D%98%20%EC%9E%90%EB%A3%8C/10_%EC%9D%B4%EB%B6%84%ED%83%90%EC%83%89_%EC%9D%B4%EB%A1%A0.pdf) | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/tree/main/10_%EC%9D%B4%EB%B6%84%20%ED%83%90%EC%83%89) | 녹화 강의 제공 | +| 2023.05.12 | 투 포인터 | [@kwakrhkr59](https://github.com/kwakrhkr59) | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/tree/main/11_%ED%88%AC%20%ED%8F%AC%EC%9D%B8%ED%84%B0/%EA%B0%95%EC%9D%98%20%EC%9E%90%EB%A3%8C) | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/tree/main/11_%ED%88%AC%20%ED%8F%AC%EC%9D%B8%ED%84%B0) | - | | 2023.05.19 | 트리 | [@dbswn](https://github.com/dbswn) | [바로가기]() | [바로가기]() | - | | 2023.05.26 | 최단 경로 | [@Dong-droid](https://github.com/Dong-droid) | [바로가기]() | [바로가기]() | - | | 2023.06.02 | 유니온 파인드 | [@bsa0322](https://github.com/bsa0322) | [바로가기]() | [바로가기]() | 2기 자료 제공 |