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..ccb01fe4 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 | | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/11_%ED%88%AC%20%ED%8F%AC%EC%9D%B8%ED%84%B0/%EB%9D%BC%EC%9D%B4%EB%B8%8C%20%EC%BD%94%EB%94%A9/11659.cpp) | 누적 합 | +| 21921 | 블로그 | | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/11_%ED%88%AC%20%ED%8F%AC%EC%9D%B8%ED%84%B0/%EB%9D%BC%EC%9D%B4%EB%B8%8C%20%EC%BD%94%EB%94%A9/21921.cpp) | 누적 합, 슬라이딩 윈도우 | +| 2470 | 두 용액 | | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/11_%ED%88%AC%20%ED%8F%AC%EC%9D%B8%ED%84%B0/%EB%9D%BC%EC%9D%B4%EB%B8%8C%20%EC%BD%94%EB%94%A9/2470.cpp) | 투 포인터 | + +## ✏️ 과제 + +### 마감기한 + +~ 5 / 16 (화) 18:59 - 과제 제출
+~ 5 / 18 (목) 23:59 - 추가 제출
+ +### 필수 + +| 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | +| :-----------------------------------------------------------------------: | :------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :-------: | :------------------------: | +| 14503 | 로봇 청소기 | | [C++_v1](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/11_%ED%88%AC%20%ED%8F%AC%EC%9D%B8%ED%84%B0/%ED%95%84%EC%88%98/14503_v1.cpp)
[C++_v2](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/11_%ED%88%AC%20%ED%8F%AC%EC%9D%B8%ED%84%B0/%ED%95%84%EC%88%98/14503_v2.cpp) | 구현, 시뮬레이션 | +| 20922 | 겹치는 건 싫어 | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/11_%ED%88%AC%20%ED%8F%AC%EC%9D%B8%ED%84%B0/%ED%95%84%EC%88%98/20922.cpp) | 투 포인터 | +| 20437 | 문자열 게임 2 | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/11_%ED%88%AC%20%ED%8F%AC%EC%9D%B8%ED%84%B0/%ED%95%84%EC%88%98/20437.cpp) | 슬라이딩 윈도우 | + +### 도전 + +| 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | +| :--------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :-------: | :--: | +| 13422 | 도둑 | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/11_%ED%88%AC%20%ED%8F%AC%EC%9D%B8%ED%84%B0/%EB%8F%84%EC%A0%84/13422.cpp) | 투 포인터, 슬라이딩 윈도우 | +| 2473 | 세 용액 | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/11_%ED%88%AC%20%ED%8F%AC%EC%9D%B8%ED%84%B0/%EB%8F%84%EC%A0%84/2473.cpp) | 투 포인터 | +--- + +### 힌트 + +
+로봇 청소기 +
+    청소할 공간이 없을 때까지 계속해서 청소하는 방식이네요. 배웠던 알고리즘과 비슷해보이지 않나요? 방향에 유의하여 풀어보아요. +
+
+ +
+겹치는 건 싫어 +
+    두 포인터를 맨 왼쪽에 두고 오른쪽에 있는 숫자를 현재 수열에 추가할 수 있을지 없을지를 생각하며 탐색해볼까요? +
+
+ +
+문자열 게임 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/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\353\217\204\354\240\204/13422.cpp" "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\353\217\204\354\240\204/13422.cpp" new file mode 100644 index 00000000..204ba829 --- /dev/null +++ "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\353\217\204\354\240\204/13422.cpp" @@ -0,0 +1,51 @@ +#include +#include +using namespace std; + +/**m개의 집에서 k보다 작은 돈을 훔칠 수 있는 경우의 수 구하기*/ +int steal(vector house, int n, int m, int k) { + int ans = 0; // 훔칠 수 있는 가짓수 + int total = 0; // 현재 도둑질한 돈 + int left = 0, right = m - 1; + + for(int i = left; i <= right; i++) { + total += house[i]; + } + if(n == m) { // 모든 집을 훔쳐야하는 경우 -> 즉시 리턴 + return total < k; + } + + while(left != n) { // 슬라이딩 윈도우 + if(total < k) { // 도둑질한 돈이 k보다 작으면 훔칠 수 있음 + ans++; + } + total -= house[left++]; + right = (right+1) % n; + total += house[right]; + } + return ans; +} +/**[백준 13422: 도둑] + * 1. 윈도우의 크기를 m으로 설정하고, 윈도우를 시계방향으로 움직이면서 도둑질할 수 있는 돈 계산 + * 2. right는 left보다 m만큼 떨어지는 집으로 설정하면, 마을이 원 모양으로 생겼으므로 right가 인덱스 범위를 벗어날 수 있음! + * -> right = (left + m)이 아닌 right = (left + m) % n + * 3. (주의) n == m인 경우, 모든 집을 훔쳐야 하므로 슬라이딩 윈도우로 탐색하지 않고 바로 현재 값 리턴 +*/ +int main() { + int t, n, m, k; + vector house; + + // 입력 + cin >> t; + while (t--) { + cin >> n >> m >> k; + house.assign(n, 0); + for (int i = 0; i < n; i++) { + cin >> house[i]; + } + + // 연산 & 출력 + cout << steal(house, n, m, k) << "\n"; + } + return 0; +} \ No newline at end of file diff --git "a/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\353\217\204\354\240\204/2473.cpp" "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\353\217\204\354\240\204/2473.cpp" new file mode 100644 index 00000000..a3b6ccc9 --- /dev/null +++ "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\353\217\204\354\240\204/2473.cpp" @@ -0,0 +1,64 @@ +#include +#include +#include +#include // abs() +#include // sort() + +#define INF 3 * 1e9 + 1 +typedef long long ll; +using namespace std; + +/**투 포인로 세 용액의 합이 가장 0에 가까운 용액 튜플 리턴*/ +tuple calSum(vector liquid) { + ll min_value = INF; + tuple ans; + + // 세 용액 중 하나(i)를 고정하고 나머지 두 용액에 해당될 용액 쌍을 투포인터로 탐색 + for (int i = 0; i < liquid.size() - 2; i++) { + // 포인터 초기화 + int left = i + 1; // 두 번째 용액 + int right = liquid.size() - 1; // 세 번째 용액 + // left는 항상 right보다 작아야 함 + while (left < right) { + ll value = liquid[i] + liquid[left] + liquid[right]; // 현재 세 용액의 합 + if (abs(value) < min_value) { + min_value = abs(value); + ans = {liquid[i], liquid[left], liquid[right]}; + } + if (value < 0) { // 현재 값이 0보다 작으면 더 큰 값을 만들어야 함 -> left++ + left++; + } else if (value > 0) { // 현재 값이 0보다 크다면 더 작은 값을 만들어야 함 -> right-- + right--; + } else { // 현재 값이 0이면 이보다 더 0보다 가까운 값은 존재하지 않으므로 탐색 종료 + return ans; + } + } + } + return ans; +} +/**[백준 2473: 세 용액] + * 1. 합이 가장 0에 가까운 세 용액의 인덱스를 각각 i, left, right로 설정 + * 2. i는 고정하고, left와 right로 투포인터를 이용해 탐색 + * 3. 현재 세 용액의 합이 0보다 작으면 left++ + * 4. 현재 세 용액의 합이 0보다 크면 right++ + * 5. 현재 세 용액의 합이 0이면 이보다 더 0에 가까운 값은 존재하지 않으므로 탐색 종료 +*/ +int main() { + int n; + vector liquid; + + // 입력 + cin >> n; + liquid.assign(n, 0); + for (int i = 0; i < n; i++) { + cin >> liquid[i]; + } + + // 연산 + sort(liquid.begin(), liquid.end()); + tuple ans = calSum(liquid); + + // 출력 + cout << get<0>(ans) << " " << get<1>(ans) << " " << get<2>(ans); + return 0; +} \ No newline at end of file diff --git "a/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\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/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\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/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/11659.cpp" "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/11659.cpp" new file mode 100644 index 00000000..974b8edb --- /dev/null +++ "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/11659.cpp" @@ -0,0 +1,43 @@ +#include +#include + +using namespace std; + +/* 누적 합 계산하기 */ +void calSum(int n, vector &sum) { + for (int i = 1; i <= n; i++) { + sum[i] += sum[i - 1]; // 첫번째 수부터 i번째 수까지의 누적 합 + } +} + +/* i번째 수부터 j번째 수까지의 합 계산하기 */ +int getPrefixSum(int i, int j, vector &sum) { + return sum[j] - sum[i - 1]; +} + +int main() { + // 입출력 성능 향상 + ios_base::sync_with_stdio(false); + cin.tie(NULL); + cout.tie(NULL); + + int n, m, i, j; + vector sum; + + // 입력 + cin >> n >> m; + sum.assign(n + 1, 0); // sum[0]을 0으로 설정 -> i-1이 0인 경우 따로 분리하지 않아도 됨 + for(int i = 1; i <= n; i++) { + cin >> sum[i]; + } + + // 연산 + calSum(n, sum); + + while (m--) { + cin >> i >> j; + // 출력 + cout << getPrefixSum(i, j, sum) << "\n"; + } + return 0; +} \ No newline at end of file diff --git "a/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/21921.cpp" "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/21921.cpp" new file mode 100644 index 00000000..dfe87330 --- /dev/null +++ "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/21921.cpp" @@ -0,0 +1,77 @@ +#include +#include + +using namespace std; +typedef pair ci; + +//슬라이딩 윈도우로 최대 방문자 수(ans)와 그 기간의 개수를 pair로 리턴 +ci slidingWindow(vector &count, int n, int x) { + // 윈도우 초기화 + int left = 1, right = x; + int visitor = 0; // 방문자 수 + int cnt = 1; // 최대 방문자 수 기간 개수 + + for (int i = left; i <= right; i++) { + visitor += count[i]; + } + int max_visitor = visitor; // 최대 방문자 수 + + while (right < n) { + visitor -= count[left++]; // 이번 윈도우에서 제외 + visitor += count[++right]; // 이번 윈도우에서 추가 + + if (visitor > max_visitor) { // 현재 방문자 수(section_visitor)가 최대 방문자 수(ans)보다 크다면 + max_visitor = visitor; // 최대 방문자 수(ans) 갱신 + cnt = 1; // 최대 방문자 수 기간 개수 초기화 + } + else if (visitor == max_visitor) { // 현재 방문자 수(section_visitor)가 최대 방문자 수(ans)와 같다면 + cnt++; // 최대 방문자 수 기간 개수 1 추가 + } + } + return {max_visitor, cnt}; +} + +ci prefixSum(vector &count, int n, int x) { + int max_visitor = 0, cnt = 0; + vector sum(n + 1, 0); // i번째 일까지의 방문자 수 누적합 저장하는 배열 + for(int i = 1; i <= n; i++) { + sum[i] = sum[i - 1] + count[i]; + } + + for(int i = x; i <= n; i++) { + int visitor = sum[i] - sum[i - x]; // i-x부터 x일간 방문자 수 + if (visitor > max_visitor) { // 최대 방문자 수 갱신 + max_visitor = visitor; + cnt = 1; + } + else if (visitor == max_visitor) { // 최대 방문자 수가 같은 경우 기간 개수 갱신 + cnt++; + } + } + return {max_visitor, cnt}; +} + +int main() { + int x, n; + vector count; + + // 입력 + cin >> n >> x; + count.assign(n + 1, 0); + for (int i = 1; i <= n; i++) { + cin >> count[i]; + } + + // 연산 + ci ans = slidingWindow(count, n, x); + // ci ans = prefixSum(count, n, x); + + // 출력 + if (ans.first == 0) { // 최대 방문자 수가 0이면 + cout << "SAD"; + } else { + cout << ans.first << "\n" << ans.second; + } + + return 0; +} \ No newline at end of file diff --git "a/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/2470.cpp" "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/2470.cpp" new file mode 100644 index 00000000..a04b4027 --- /dev/null +++ "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/2470.cpp" @@ -0,0 +1,50 @@ +#include +#include +#include //abs() +#include //sort() + +using namespace std; +typedef pair ci; + +/* 투 포인로 두 용액의 합이 가장 0에 가까운 용액 쌍 리턴 */ +ci mixLiquid(vector &liquid, int left, int right){ + int min_value = abs(liquid[left] + liquid[right]); // 두 용액의 합의 값 중 가장 가까운 값 + ci ans = {liquid[left], liquid[right]}; // 합이 가장 0에 가까운 두 용액의 특성값 + + // left는 항상 right보다 작아야 함 + while (left < right) { + int value = liquid[left] + liquid[right]; // 두 용액 혼합 + if(abs(value) < min_value) { // 현재 합이 min_value보다 더 0에 가까우면 + min_value = abs(value); // min_value 갱신 + ans = {liquid[left], liquid[right]}; // ans 갱신 + } + if (value < 0) { // 현재 값이 0보다 작다면 더 큰 값을 만들어야 함 -> lef++ + left++; + } else if (value > 0) { // 현재 값이 0보다 크다면 더 작은 값을 만들어야 함 -> right-- + right--; + } else { // 현재 값이 0이면 이보다 더 0보다 가까운 값은 존재하지 않으므로 탐색 종료 + break; + } + } + return ans; +} + +int main() { + int n; + vector liquid; + + // 입력 + cin >> n; + liquid.assign(n, 0); + for (int i = 0; i < n; i++) { + cin >> liquid[i]; + } + + // 연산 + sort(liquid.begin(), liquid.end()); + ci ans = mixLiquid(liquid, 0, n - 1); + + // 출력 + cout << ans.first << " " << ans.second; + return 0; +} \ No newline at end of file diff --git "a/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\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/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\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/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/14503_v1.cpp" "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/14503_v1.cpp" new file mode 100644 index 00000000..83d3857b --- /dev/null +++ "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/14503_v1.cpp" @@ -0,0 +1,74 @@ +#include + +using namespace std; + +const int SIZE = 50; +const int CLEAN = 2; +int n, m, cnt = 0; // 세로 크기, 가로 크기, 청소한 칸 개수 + +int board[SIZE][SIZE]; // (0: 빈 칸, 1: 벽, 2: 청소 완료) +int dx[4] = {0, 1, 0, -1}, dy[4] = {-1, 0, 1, 0}; // 북 동 남 서 + +void dfs(int row, int col, int dir) { + // 1. 현재 위치 청소 + if(board[row][col] != CLEAN) { + cnt++; + } + board[row][col] = CLEAN; + + // [현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 있는가] + // 3. 현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 있는 경우 + for(int i = 0; i < 4; i++) { // 3-1. 반시계 방향으로 90º 회전 + int new_dir = (dir-i+3) % 4; + int new_row = row + dy[new_dir], new_col = col + dx[new_dir]; + + if(board[new_row][new_col] == 0) { // 3-2. 아직 청소되지 않은 빈 칸 발견 + dfs(new_row, new_col, new_dir); // 한 칸 전진 + return; + } + } + + // 2. 현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 없는 경우 + int back_dir = (dir+2) % 4; + int back_row = row + dy[back_dir], back_col = col + dx[back_dir]; + + // [바라보는 방향을 유지한 채로 한 칸 후진할 수 있는가] + // 2-2. 뒤쪽 칸이 벽이라 후진할 수 없는 경우 + if(board[back_row][back_col] == 1) { + return; + } + // 2-1. 바라보는 방향을 유지한 채로 한 칸 후진 + dfs(back_row, back_col, dir); // 방향 유지한 상태로 후진 (2-3) + return; +} + +/* + * [로봇 청소기 작동] + * 1. 현재 칸이 아직 청소되지 않은 경우, 현재 칸을 청소한다. + * 2. 현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 없는 경우, + * 2-1. 바라보는 방향을 유지한 채로 한 칸 후진할 수 있다면 한 칸 후진하고 1번으로 돌아간다. + * 2-2. 바라보는 방향의 뒤쪽 칸이 벽이라 후진할 수 없다면 작동을 멈춘다. + * 3. 현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 있는 경우, + * 3-1. 반시계 방향으로 90º 회전한다. + * 3-2. 바라보는 방향을 기준으로 앞쪽 칸이 청소되지 않은 빈 칸인 경우 한 칸 전진한다. + * 3-3. 1번으로 돌아간다. +*/ + +int main() { + int r, c, d; // 로봇 청소기 정보 + + // 입력 + cin >> n >> m; + cin >> r >> c >> d; + + for(int i = 0; i < n; i++) { + for(int j = 0; j < m; j++) { + cin >> board[i][j]; + } + } + + // 연산 & 출력 + dfs(r, c, d); + cout << cnt; + return 0; +} \ No newline at end of file diff --git "a/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/14503_v2.cpp" "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/14503_v2.cpp" new file mode 100644 index 00000000..5143611e --- /dev/null +++ "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/14503_v2.cpp" @@ -0,0 +1,79 @@ +#include +#include + +using namespace std; + +const int CLEAN = 2; + +int dx[4] = {0, 1, 0, -1}, dy[4] = {-1, 0, 1, 0}; // 북 동 남 서 + +int clean(int n, int m, int r, int c, int d, vector> &board) { + int cnt = 0; + + while(true) { + // 1. 현재 칸이 아직 청소되지 않은 경우, 현재 칸을 청소한다. + if(board[r][c] != CLEAN) { + cnt++; + } + board[r][c] = CLEAN; + + bool find = false; // 현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 있는가 + for(int i = 0; i < 4; i++) { + int nd = (d-i+3) % 4; + int nr = r + dy[nd], nc = c + dx[nd]; + + if(board[nr][nc] == 0) { // 3-2. 아직 청소되지 않은 빈 칸 발견 + find = true; + r = nr; c = nc; d = nd; + break; + } + } + if(find) { // 3. 현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 있는 경우 1번으로 돌아감 + continue; + } + + // 2. 현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 없는 경우 + int bd = (d+2) % 4; + int br = r + dy[bd], bc = c + dx[bd]; + + // [바라보는 방향을 유지한 채로 한 칸 후진할 수 있는가] + // 2-2. 뒤쪽 칸이 벽이라 후진할 수 없는 경우 + if(board[br][bc] == 1) { + return cnt; + } + // 2-1. 바라보는 방향을 유지한 채로 한 칸 후진 + r = br; c = bc; + } + return cnt; +} + +/* + * [로봇 청소기 작동] + * 1. 현재 칸이 아직 청소되지 않은 경우, 현재 칸을 청소한다. + * 2. 현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 없는 경우, + * 2-1. 바라보는 방향을 유지한 채로 한 칸 후진할 수 있다면 한 칸 후진하고 1번으로 돌아간다. + * 2-2. 바라보는 방향의 뒤쪽 칸이 벽이라 후진할 수 없다면 작동을 멈춘다. + * 3. 현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 있는 경우, + * 3-1. 반시계 방향으로 90º 회전한다. + * 3-2. 바라보는 방향을 기준으로 앞쪽 칸이 청소되지 않은 빈 칸인 경우 한 칸 전진한다. + * 3-3. 1번으로 돌아간다. +*/ + +int main() { + int n, m, r, c, d; + vector> board; + + // 입력 + cin >> n >> m; + cin >> r >> c >> d; + board.assign(n, vector (m, 0)); + for(int i = 0; i < n; i++) { + for(int j = 0; j < m; j++) { + cin >> board[i][j]; + } + } + + // 연산 & 출력 + cout << clean(n, m, r, c, d, board); + return 0; +} \ No newline at end of file diff --git "a/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/20437.cpp" "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/20437.cpp" new file mode 100644 index 00000000..242d8381 --- /dev/null +++ "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/20437.cpp" @@ -0,0 +1,61 @@ +#include +#include +#include + +using namespace std; +typedef pair ci; +const int MAX_ALPHA = 26; // 알파벳 개수 + +/**문자를 k개 포함하는 가장 짧은 문자열과 가장 긴 문자열의 쌍 구하기*/ +ci solution(string w, int k) { + vector> char_idx(MAX_ALPHA); + int min_len = w.size(); // 가장 짧은 문자열 길이 초기화 + int max_len = -1; // 가장 긴 문자열 길이 초기화 + + for (int i = 0; i < w.size(); i++) { + char_idx[w[i] - 'a'].push_back(i); // 문자의 인덱스 저장 + } + + for (int i = 0; i < MAX_ALPHA; i++) { // 각 문자를 포함하는 문자열 확인 + if (char_idx[i].size() < k) { // 해당 알파벳이 k번 이상 등장하지 않으면 탐색 X + continue; + } + int left = 0, right = k - 1; // 포인터 초기화 + while (right < char_idx[i].size()) { + int tmp_len = char_idx[i][right] - char_idx[i][left] + 1; + min_len = min(min_len, tmp_len); + max_len = max(max_len, tmp_len); + left++; // 윈도우 이동 + right++; + } + } + return {min_len, max_len}; +} +/**[백준 20437: 문자열 게임2] + * 1. 각 알파벳의 위치 인덱스를 char_idx에 저장 + * 2. 윈도우의 크기를 k로 설정하고 윈도우를 오른쪽으로 이동시키며 + * 가장 짧은 문자열과 가장 긴 문자열 탐색 + * 이때 각 문자열의 길이는 char_idx[i][right] - char_idx[i][left] + 1 +*/ +int main() { + int t, k; + string w; + + // 입력 + cin >> t; + + while (t--) { + cin >> w >> k; + + // 연산 + ci ans = solution(w, k); + + // 출력 + if (ans.second == -1) { + cout << -1 << "\n"; + } else { + cout << ans.first << " " << ans.second << "\n"; + } + } + return 0; +} \ No newline at end of file diff --git "a/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/20922.cpp" "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/20922.cpp" new file mode 100644 index 00000000..741e007f --- /dev/null +++ "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/20922.cpp" @@ -0,0 +1,46 @@ +#include +#include +#include + +using namespace std; +const int MAX_NUM = 100001; //수열 내 숫자 최대값 + +/**같은 정수를 k개 이하로 포함하는 최장 연속 부분 수열 길이 구하기*/ +int getMaxLen(vector &number, int n, int k) { + vector count(MAX_NUM, 0); // 수열 내 각 숫자의 개수 저장 + int left = 0, right = 0; // 포인터 초기화 + int max_len = 0; // 최대 수열 길이 초기화 + + while (right < n) { + // right를 오른쪽으로 옮겨가면서 right번째 숫자를 수열에 추가할 수 있을 지 판단 + if (count[number[right]] >= k) { // right에 있는 숫자의 개수가 k가 넘으면 -> 추가 불가 + count[number[left]]--; // left 숫자 삭제 + left++; + } else { // right에 있는 숫자의 개수가 k보다 작으면 -> 추가 가능 + count[number[right]]++; // right 숫자 추가 + right++; + max_len = max(max_len, right - left); // 최대 수열 길이 갱신 + } + } + return max_len; +} +/**[백준 20922: 겹치는 건 싫어] + * 1. 맨 왼쪽부터 투포인터를 이용해 탐색하며 left와 right 사이에 있는 숫자들의 개수를 count에 저장 + * 2. 오른쪽에 있는 숫자를 수열에 추가할 수 있으면 추가하고 right++ + * 3. 오른쪽에 있는 숫자를 수열에 추가할 수 없으면 현재 수열의 맨 왼쪽 숫자를 삭제하고 left 이동 +*/ +int main() { + int n, k; + vector numbers; + + //입력 + cin >> n >> k; + numbers.assign(n, 0); + for (int i = 0; i < n; i++) { + cin >> numbers[i]; + } + + //연산 & 출력 + cout << getMaxLen(numbers, n, k); + return 0; +} \ No newline at end of file diff --git "a/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\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/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\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/12_\355\212\270\353\246\254/README.md" "b/12_\355\212\270\353\246\254/README.md" index e69de29b..3ffc8cdf 100644 --- "a/12_\355\212\270\353\246\254/README.md" +++ "b/12_\355\212\270\353\246\254/README.md" @@ -0,0 +1,75 @@ +# 트리 (Tree) + +[메인으로 돌아가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4) + +## 💻 튜터링 + +### 라이브 코딩 + +| 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | +| :-----------------------------------------------------------------------: | :----------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :----------: | :--------: | +| 1991 | 트리 순회 | | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/12_%ED%8A%B8%EB%A6%AC/%EB%9D%BC%EC%9D%B4%EB%B8%8C%20%EC%BD%94%EB%94%A9/1991.cpp) | 트리 순회 | +| 4803 | 트리 | | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/12_%ED%8A%B8%EB%A6%AC/%EB%9D%BC%EC%9D%B4%EB%B8%8C%20%EC%BD%94%EB%94%A9/4803.cpp) | 트리, DFS | + +## ✏️ 과제 + +### 마감기한 + +~ 5 / 23 (화) 18:59 - 과제 제출
+~ 5 / 25 (목) 23:59 - 추가 제출
+ +### 필수 + +| 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | +| :-----------------------------------------------------------------------: | :------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :-------: | :------------------------: | +| 3190 | | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/12_%ED%8A%B8%EB%A6%AC/%ED%95%84%EC%88%98/3190.cpp) | 구현, 시뮬레이션, 자료구조 | +| 15681 | 트리와 쿼리 | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/12_%ED%8A%B8%EB%A6%AC/%ED%95%84%EC%88%98/15681.cpp) | 트리, 그래프 탐색, DP | +| 5639 | 이진 검색 트리 | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/12_%ED%8A%B8%EB%A6%AC/%ED%95%84%EC%88%98/5639.cpp) | 트리, 그래프 탐색 | + +### 도전 + +| 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | +| :--------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :-------: | :--: | +| 1967 | 트리의 지름 | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/12_%ED%8A%B8%EB%A6%AC/%EB%8F%84%EC%A0%84/1967.cpp) | 트리, 그래프 탐색 | +| 24545 | Y | | [C++](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/12_%ED%8A%B8%EB%A6%AC/%EB%8F%84%EC%A0%84/24545.cpp) | 트리 그래프 탐색, DP | +--- + +### 힌트 + +
+ +
+    뱀의 머리와 꼬리에 변화가 생기고 있네요! 어떤 자료구조가 필요할까요? 뱀의 현재 위치를 직접 나타내보는 것도 좋을 것 같네요. +
+
+ +
+트리와 쿼리 +
+    모든 정점을 각각 루트로 하는 서브트리에서의 정점의 수를 빠르게 구해 둘 방법이 무엇일까요? 앞서 배운 알고리즘을 떠올려보세요! +
+
+ +
+이진 검색 트리 +
+    전위 순회한 결과를 루트와 왼쪽 오른쪽으로 나눠보고 후위 순회의 순서를 떠올려보세요! +
+
+ +
+트리의 지름 +
+    지름을 이루는 노드의 특징은 무엇일까요? +
+
+ +
+Y +
+    사용할 수 있는 정점의 종류를 고려해서 트리의 모양을 추측해보세요! 또 N이 생각보다 큰 것 같아요! +
+
+ + +--- diff --git "a/12_\355\212\270\353\246\254/\352\260\225\354\235\230 \354\236\220\353\243\214/12_\355\212\270\353\246\254_\353\254\270\354\240\234\355\225\264\354\204\244.pdf" "b/12_\355\212\270\353\246\254/\352\260\225\354\235\230 \354\236\220\353\243\214/12_\355\212\270\353\246\254_\353\254\270\354\240\234\355\225\264\354\204\244.pdf" new file mode 100644 index 00000000..2bb1c381 Binary files /dev/null and "b/12_\355\212\270\353\246\254/\352\260\225\354\235\230 \354\236\220\353\243\214/12_\355\212\270\353\246\254_\353\254\270\354\240\234\355\225\264\354\204\244.pdf" differ diff --git "a/12_\355\212\270\353\246\254/\352\260\225\354\235\230 \354\236\220\353\243\214/12_\355\212\270\353\246\254_\354\235\264\353\241\240.pdf" "b/12_\355\212\270\353\246\254/\352\260\225\354\235\230 \354\236\220\353\243\214/12_\355\212\270\353\246\254_\354\235\264\353\241\240.pdf" new file mode 100644 index 00000000..e7c5dd8e Binary files /dev/null and "b/12_\355\212\270\353\246\254/\352\260\225\354\235\230 \354\236\220\353\243\214/12_\355\212\270\353\246\254_\354\235\264\353\241\240.pdf" differ diff --git "a/12_\355\212\270\353\246\254/\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/12_\355\212\270\353\246\254/\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/\353\217\204\354\240\204/1967.cpp" "b/12_\355\212\270\353\246\254/\353\217\204\354\240\204/1967.cpp" new file mode 100644 index 00000000..44aa26b4 --- /dev/null +++ "b/12_\355\212\270\353\246\254/\353\217\204\354\240\204/1967.cpp" @@ -0,0 +1,71 @@ +#include +#include + +using namespace std; +typedef pair ci; + +/* weight가 더해지면서 탐색의 depth가 늘어나고 최종적으로 node와 가중치가 return된다 +* return 될 때 cur 노드의 자식 노드 중에서 weight가 가장 큰 노드로 갱신 +* 결국 root 에서 가장 먼 노드 번호와 weigth가 return됨!! +*/ +ci dfs(int cur, int prev, vector>& graph, int weight) { + int max_node = cur; + int max_edge = weight; + + for (int i = 0; i < graph[cur].size(); i++) { + + int next_node = graph[cur][i].first; + int next_edge = graph[cur][i].second; + + if (next_node == prev) { + continue; + } + + ci search = dfs(next_node, cur, graph, weight+next_edge); // 자식 노드에 대해서 dfs 탐섹 + + if (search.second > max_edge) { // 자식 노드의 return 값 중 큰 걸로 갱신됨 + max_node = search.first; + max_edge = search.second; + } + } + return { max_node, max_edge }; +} + +/** +* Hint : 지름을 이루는 노드의 특징은 무엇일까요? + * [트리의 지름] + * + * 1. 지름을 이루는 두 점은 모두 리프 노드 + * 2. 임의의 한 노드에서 가장 멀리 있는 노드(리프 노드)는 지름을 이루는 노드 중 하나 + * 3. 지름을 이루는 노드에서 가장 멀리 있는 노드는 지름을 이루는 다른 노드 + * + * 부모->자식의 방향만 저장하면 리프 노드에서 다른 리프 노드로 탐색할 수 없으므로 무방향 그래프로 저장 + */ + + + +int main() { + // 입력 + int n; + cin >> n; + vector> graph(n + 1, vector(0)); + int v1, v2, e; + for (int i = 0; i < n - 1; i++) { + cin >> v1 >> v2 >> e; + graph[v1].push_back({ v2,e }); + graph[v2].push_back({ v1,e }); + } + + // 연산 + + // 1. 루트에서 가장 먼 노드 찾기 + ci farmost = dfs(1, -1, graph, 0); + + // 2. 1에서 찾은 노드에서 가장 먼 노드 찾기 + ci another_farmost = dfs(farmost.first, -1, graph, 0); + + // 출력 + cout << another_farmost.second; + + return 0; +} \ No newline at end of file diff --git "a/12_\355\212\270\353\246\254/\353\217\204\354\240\204/24545.cpp" "b/12_\355\212\270\353\246\254/\353\217\204\354\240\204/24545.cpp" new file mode 100644 index 00000000..eba555ba --- /dev/null +++ "b/12_\355\212\270\353\246\254/\353\217\204\354\240\204/24545.cpp" @@ -0,0 +1,69 @@ +/* +* HINT : 사용할 수 있는 정점의 종류를 고려해서 트리의 모양을 추측해보세요! +* +*/ +#include +#include +#include +#include + +using namespace std; + +int dfs(int curr, int prev, vector>& tree, vector>& cnt_node) { + if (cnt_node[prev][curr]) { // 이미 저장해둔 값 있으면 바로 리턴 + return cnt_node[prev][curr]; + } + int cnt = 0; + + for (int next : tree[curr]) { + if (next == prev) { // 직전에 방문한 노드는 돌아가지 않음 -> 만약 이부분이 없다면? 무한루프 + continue; + } + cnt = max(cnt, dfs(next, curr, tree, cnt_node)); // 최댓값 갱신 + } + //cout << prev << " -> " << curr << ' ' << cnt + 1 << '\n'; // 디버깅용 + return cnt_node[prev][curr] = cnt + 1; +} + +int getMaxYTree(int n, vector>& tree, vector>& cnt_node) { + int ans = 0; + + // Y-트리의 중심이 될 노드를 순차적으로 탐색 + for (int curr = 1; curr <= n; curr++) { + if (tree[curr].size() < 3) { // 간선의 수 < 3인 경우 중심이 될 수 없음 + continue; + } + vector cnt; // 해당노드(curr)에서 나오는 간선에서 얻을 수 있는 노드의 수 저장 + + for (int next : tree[curr]) { + cnt.push_back(dfs(next, curr, tree, cnt_node)); + } + sort(cnt.begin(), cnt.end(), greater<>()); + ans = max(ans, cnt[0] + cnt[1] + cnt[2] + 1); // 가장 많은 노드를 선택할 수 있는 경우 세가지 + 중심점(curr) + } + + return ans; +} + +int main() { + int n, u, w; + vector> tree; // 인접리스트 형태로 저장 + vector> cnt_node; // 간선에 노드 수 저장 + + // 입력 + cin >> n; + + // 입력 + 초기화 + tree.assign(n + 1, vector(0)); + cnt_node.assign(n + 1, map()); + + for (int i = 0; i < n - 1; i++) { + cin >> u >> w; + tree[u].push_back(w); + tree[w].push_back(u); + } + + // 연산 + 출력 + cout << getMaxYTree(n, tree, cnt_node); + return 0; +} \ No newline at end of file diff --git "a/12_\355\212\270\353\246\254/\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/12_\355\212\270\353\246\254/\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/12_\355\212\270\353\246\254/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/1991.cpp" "b/12_\355\212\270\353\246\254/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/1991.cpp" new file mode 100644 index 00000000..f166bf41 --- /dev/null +++ "b/12_\355\212\270\353\246\254/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/1991.cpp" @@ -0,0 +1,58 @@ +#include +#include + +using namespace std; + +map> tree; + +// 전위 순회는 V - L - R +void preorder(char v) { + if (v == '.') { + return; + } + cout << v; + preorder(tree[v].first); + preorder(tree[v].second); +} + +// 중위 순회 L - V - R +void inorder(char v) { + if (v == '.') { + return; + } + + inorder(tree[v].first); + cout << v; + inorder(tree[v].second); +} + +// 후위 순회 L - R - V +void postorder(char v) { + if (v == '.') { + return; + } + + postorder(tree[v].first); + postorder(tree[v].second); + cout << v; +} + +int main() { + int n; + char root, left, right; + + // 입력 + cin >> n; + while (n--) { + cin >> root >> left >> right; + tree[root] = { left, right }; + } + + // 연산 + 출력 + preorder('A'); + cout << '\n'; + inorder('A'); + cout << '\n'; + postorder('A'); + return 0; +} \ No newline at end of file diff --git "a/12_\355\212\270\353\246\254/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/4803.cpp" "b/12_\355\212\270\353\246\254/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/4803.cpp" new file mode 100644 index 00000000..51caf7ce --- /dev/null +++ "b/12_\355\212\270\353\246\254/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/4803.cpp" @@ -0,0 +1,87 @@ +#include +#include + +using namespace std; + +// 결과 출력 함수 +void printResult(int tc, int cnt) { + cout << "Case " << tc << ": "; + + switch (cnt) { + case 0: + cout << "No trees.\n"; + break; + case 1: + cout << "There is one tree.\n"; + break; + default: + cout << "A forest of " << cnt << " trees.\n"; + } + return; +} + +void dfs(bool& flag, int cur, int prev, vector>& graph, vector& visited) { + + if (visited[cur]) { // 방문했던 곳을 또 방문했다면 트리가 아니다 + flag = false; + return; + } + + visited[cur] = true; // 방문 체크 + + for (int next : graph[cur]) { + if (next == prev) { + continue; + } + dfs(flag, next, cur, graph, visited); + } + return ; +} + +/* +* 각 그래프가 트리인지 아닌지 판단 +* 사이클이 생기면 트리 아님 +* 사이클이 생긴다 -> DFS로 자기 자신으로 돌아올 수 있다. +*/ + +int main() { + int n, m, t, v1, v2; + + for (t = 1;;t++) { // 테스트 케이스 번호 + + // 입력 + cin >> n >> m; + + if (!n && !m) { // 종료 조건 + break; + } + + // 그래프 입력 + vector> graph(n+1, vector(0)); + for (int i = 0; i < m; i++) { + cin >> v1 >> v2; + graph[v1].push_back(v2); + graph[v2].push_back(v1); + } + + int cnt = 0; // 트리 수 카운트 + vector visited(n + 1, false); // 방문 표시 + + for (int i = 1; i <= n; i++) { + if (visited[i]) { + continue; + } + + bool flag = true; // 트리인지 여부 저장하는 변수 + dfs(flag, i, 0, graph, visited); + if (flag) { + cnt++; + } + + } + + // 출력 + printResult(t, cnt); + } + return 0; +} diff --git "a/12_\355\212\270\353\246\254/\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/12_\355\212\270\353\246\254/\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/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..e2301368 --- /dev/null +++ "b/12_\355\212\270\353\246\254/\355\225\204\354\210\230/15681.cpp" @@ -0,0 +1,57 @@ +#include +#include +#include + +using namespace std; + +/* + * 트리의 정점의 수 구하기 응용 문제 + * + * 1. 루트에서 DFS를 사용하여 탐색 + * 2. 각 노드를 루트로 하는 서브트리의 정점 수를 재귀적으로 벡터에 저장 + * - 서브트리에 속한 정점의 개수를 저장하는 dp 배열을 1로 초기화 + * - 탐색 시 현재 정점의 자식 노드만 탐색해서 현재 정점의 dp 값에 더해줌 + * 3. 쿼리로 주어지는 정점의 서브트리의 정점의 개수를 dp에서 찾아서 출력 + */ + +void dfs(int cur, int prev, vector>& tree, vector& dp) { + + for (int i = 0; i < tree[cur].size(); i++) { // 현재 정점의 자식 노드 탐색 + if (tree[cur][i] == prev) { + continue; + } + dfs(tree[cur][i], cur,tree, dp); + dp[cur] += dp[tree[cur][i]]; // 자식 노드의 dp값 더해주기 + } + + return; +} + +int main() { + + ios::sync_with_stdio(false); + cin.tie(0); + cout.tie(0); + + // 입력 + int n, r, q, u, v; + cin >> n >> r >> q; + + vector>tree(n + 1, vector(0)); + + for (int i = 0; i < n - 1; i++) { + cin >> u >> v; + tree[u].push_back(v); + tree[v].push_back(u); + } + + // 연산 + vectordp(n + 1, 1); // 자신도 자신을 루트로 하는 서브트리에 포함되므로 0이 아닌 1로 dp 초기값 설정 + dfs(r, 0,tree, dp); + + // 출력 + while (q--) { + cin >> u; + cout < +#include +#include +#include + +using namespace std; +typedef pair ci; + +/**뱀 게임이 종료되는 시간 계산*/ +int game(int n, vector> &state, map &direction) { + int dx[4] = {0, 1, 0, -1}; // 동(→), 남(↓), 서(←), 북(↑) + int dy[4] = {1, 0, -1, 0}; + int time = 0; // 게임 시간 + int dir = 0; // 뱀의 방향 + int x, y, nx, ny; + + deque snake; // 뱀의 위치 + snake.push_back({1, 1}); // 뱀의 시작 좌표 추가 + state[1][1] = 2; // (1, 1)에 뱀이 있음을 표시 + + while (true) { + x = snake.front().first; // 뱀의 머리 좌표 + y = snake.front().second; + if (direction[time] != 0) { // 뱀의 방향 변환 정보가 있으면 + dir = (dir + direction[time]) % 4; // 뱀의 방향 갱신 + } + time++; // 게임 시간 1초 추가 + nx = x + dx[dir]; // 뱀 머리의 다음 좌표 + ny = y + dy[dir]; + + // 뱀의 머리가 벽에 부딪히거나 자기 자신의 몸과 부딪히면 게임 종료 + if (!(0 < nx && nx <= n) || !(0 < ny && ny <= n) || state[nx][ny] == 2) { + break; + } + + snake.push_front({nx, ny}); // 뱀의 머리 좌표 추가 + if (state[nx][ny] != 1) { // 새로 이동한 좌표에 사과가 없으면 꼬리 위치 비워주기 + state[snake.back().first][snake.back().second] = 0; + snake.pop_back(); + } + state[nx][ny] = 2; + } + return time; +} +/**[백준 3190: 뱀] + * 뱀의 머리와 꼬리 좌표에 대한 접근 필요 -> deque 사용! + * state에 사과가 존재하면 해당 위치를 1, 뱀이 존재하면 2, 아무것도 없으면 0으로 설정 + * 1. 뱀의 첫 시작 좌표인 {1, 1}을 s에 추가 + * 2. 현재 뱀의 머리가 있는 좌표를 {x, y}로 받기 + * 3. 뱀의 방향이 바뀌면 방향을 업데이트하고, 새로운 뱀의 머리 좌표를 {nx, ny}로 설정 + * 4. 게임 시간 업데이트(time++) + * 4. 뱀의 머리가 벽이나 몸에 부딪히면 while문 종료 + * 5-1. 새로 이동한 좌표를 s 앞부분에 추가 + * 5-2. 새로 이동한 좌표에 사과가 없으면 기존 꼬리 좌표 값을 0으로 바꾸고 s에서 pop + * -> 사과가 있으면 몸길이가 1 늘어나지만 사과가 없으면 몸길이가 변하지 않으므로 + * 6. 새로 이동한 좌표를 2로 표시 +*/ +int main() { + int n, k, l, x; + char c; + vector> state; + map direction; + + // 입력 + cin >> n >> k; + state.assign(n + 1, vector(n + 1, 0)); + while (k--) { + int a, b; + cin >> a >> b; + state[a][b] = 1; //사과 위치 표시 + } + + cin >> l; + while (l--) { + cin >> x >> c; + if (c == 'D') { + direction[x] = 1; // 오른쪽으로 회전 + } else { + direction[x] = 3; // 왼쪽으로 회전 + } + } + + // 연산 + int time = game(n, state, direction); + + // 출력 + cout << time; + 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..42a600fc --- /dev/null +++ "b/12_\355\212\270\353\246\254/\355\225\204\354\210\230/5639.cpp" @@ -0,0 +1,53 @@ +#include +#include + +using namespace std; + +void postOrder(int left, int right, vector& tree) { + if (left > right) { + return; + } + + int root = tree[left];//이해하기 쉽게 루트 따로 저장해주자! + + //루트보다 처음으로 큰 노드 인덱스 찾기 -> left, right새로 설정하기 위해서! + int tmp = left + 1; + for (int i = left+1 ; i <= right ; i++) { + if (tree[i] > root) { + tmp = i; + break; + } + } + + //후위 순회 순으로 다시 탐색 + postOrder(left + 1, tmp - 1,tree);//루트보다 작은 노드들 + postOrder(tmp, right, tree);//루트보다 큰 노드들 + + //left, right 탐색 끝났으므로 root 출력 + cout << root << '\n'; +} + +/* +* 이진 검색 트리 : 루트의 왼쪽 +* 이진 검색 트리를 전위 순회환 결과 -> 후위 순회한 결과 +* 전위 순회 : 루트 왼쪽 오른쪽 -> 후위 순회 : 왼쪽 오른쪽 루트 +* -> 탐색 결과 : 루트 -> 루트보다 작은 노드(왼쪽) -> 루트보다 큰 노드(오른쪽) +* -> 루트를 기준으로 left, right 나눠서 후위 순회 순으로 다시 탐색 +*/ + +int main() { + + ios::sync_with_stdio(false); + cin.tie(0); + cout.tie(0); + + //입력 + int num; + vector tree; + while (cin >> num) { + tree.push_back(num); + } + + //연산 + 출력 + postOrder(0, tree.size() - 1, tree); +} \ No newline at end of file diff --git "a/12_\355\212\270\353\246\254/\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/12_\355\212\270\353\246\254/\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/13_\354\265\234\353\213\250 \352\262\275\353\241\234/README.md" "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/README.md" index e69de29b..15566a15 100644 --- "a/13_\354\265\234\353\213\250 \352\262\275\353\241\234/README.md" +++ "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/README.md" @@ -0,0 +1,76 @@ +# 최단 경로 (Shortest Path) + +[메인으로 돌아가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4) + +## 💻 튜터링 + +### 라이브 코딩 + +| 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | +| :-----------------------------------------------------------------------: | :----------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :----------: | :--------: | +| 1753 | 최단경로 | | [바로가기]() | 다익스트라 | +| 11404 | 플로이드 | | [바로가기]() | 플로이드-워셜 | +| 11657 | 타임머신 | | [바로가기]() | 벨만-포드 | + +## ✏️ 과제 + +### 마감기한 + +~ 5 / 30 (화) 18:59 - 과제 제출
+~ 6 / 1 (목) 23:59 - 추가 제출
+ +### 필수 + +| 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | +| :-----------------------------------------------------------------------: | :------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :-------: | :------------------------: | +| 15685 | 드래곤 커브 | | [C++]() | 구현, 시뮬레이션 | +| 1238 | 파티 | | [C++]() | 다익스트라 | +| 2458 | 키 순서 | | [C++]() | 플로이드-워셜 | + +### 도전 + +| 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | +| :--------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :-------: | :--: | +| 프로그래머스 | 합승 택시 요금 | **Lv.3** | [C++]() | 플로이드-워셜 | +| 1865 | 웜홀 | | [C++]() | 벨만-포드 | +--- + +### 힌트 + +
+드래곤 커브 +
+    뱀의 머리와 꼬리에 변화가 생기고 있네요! 어떤 자료구조가 필요할까요? 뱀의 현재 위치를 직접 나타내보는 것도 좋을 것 같네요. +
+
+ +
+파티 +
+    이제 어떤 지점을 가기만 하는 게 아니라 오기도 해야 하니 다익스트라 알고리즘을 여러 번 사용해야겠습니다! +
+
+ +
+키 순서 +
+    두 사람 사이의 키 순위를 비교해볼까요? 나와 상대방과의 키 순위를 안다는 것은 내가 상대방과의 키 우열을 알거나 상대방이 나와의 키 우열을 안다는 것과 같습니다. +
+
+ +
+합승 택시 요금 +
+    함께 합승할 수 있는 지점은 총 몇 개인가요? 계산에 고려해야 할 가능한 시작, 도착 지점의 쌍이 어떻게 될까요? +
+
+ +
+웜홀 +
+    시간이 뒤로 갈 수 있다네요? 음수 가중치일때 사용할 수 있는 알고리즘을 배웠었죠! 것보다 벨만 포드는 분명 출발점이 특정한 한 점일때 가능한 알고리즘이라고 배웠는데,시작지점이 정해져있지 않네요. 그런데 특정 정점 하나만 확인하면 해당 정점과 단절된 노드가 포함된 음수 사이클을 발견할 수 없죠! 우리는 최단거리에는 관심이 없고, 오로지 음수 사이클의 존재 여부만 확인하고 싶은 상황에서 어떻게 하면 될까요? +
+
+ + +--- diff --git "a/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\352\260\225\354\235\230 \354\236\220\353\243\214/13_\354\265\234\353\213\250\352\262\275\353\241\234_\353\254\270\354\240\234\355\225\264\354\204\244.pdf" "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\352\260\225\354\235\230 \354\236\220\353\243\214/13_\354\265\234\353\213\250\352\262\275\353\241\234_\353\254\270\354\240\234\355\225\264\354\204\244.pdf" new file mode 100644 index 00000000..748ad33b Binary files /dev/null and "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\352\260\225\354\235\230 \354\236\220\353\243\214/13_\354\265\234\353\213\250\352\262\275\353\241\234_\353\254\270\354\240\234\355\225\264\354\204\244.pdf" differ diff --git "a/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\352\260\225\354\235\230 \354\236\220\353\243\214/13_\354\265\234\353\213\250\352\262\275\353\241\234_\354\235\264\353\241\240.pdf" "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\352\260\225\354\235\230 \354\236\220\353\243\214/13_\354\265\234\353\213\250\352\262\275\353\241\234_\354\235\264\353\241\240.pdf" new file mode 100644 index 00000000..c55739f9 Binary files /dev/null and "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\352\260\225\354\235\230 \354\236\220\353\243\214/13_\354\265\234\353\213\250\352\262\275\353\241\234_\354\235\264\353\241\240.pdf" differ diff --git "a/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\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/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\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/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..c30faf75 --- /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,64 @@ +#include +#include +#include + +using namespace std; +typedef pair ci; +const int INF = 1e5; // V * (가중치의 최대값) + +//다익스트라 +vector dijkstra(int s, int n, vector> &graph) { + vector dist(n + 1, INF); //dist 배열을 INF로 초기화 + priority_queue, greater> pq; //<시작점부터의 거리, 정점> + + //시작 정점 초기화 + dist[s] = 0; + pq.push({0, s}); //pq queue에 시작점 저장 + while (!pq.empty()) { //갱신할 정점이 있을 때까지 + int weight = pq.top().first; //현재 정점까지의 경로값 + int node = pq.top().second; //현재 탐색하려는 정점 + //탐색하지 않은 정점 중 시작점에서 가장 가까운 정점 + pq.pop(); + + if (weight > dist[node]) { //이미 더 작은 값으로 기록된 정점이 있다면 + continue; + } + for (int i = 0; i < graph[node].size(); i++) { //node와 연결된 모든 정점에 대해 + int next_node = graph[node][i].first; //연결된 정점 + int next_weight = weight + graph[node][i].second; //시작점으로부터 현재 node를 거쳐 + //다음 정점까지 가는 경로값 + if (next_weight < dist[next_node]) { //최단 경로 값이 갱신된다면 + dist[next_node] = next_weight; + pq.push({next_weight, next_node}); + } + } + } + return dist; +} + +int main() +{ + ios_base::sync_with_stdio(false); + cin.tie(NULL), cout.tie(NULL); + //입력 + int n, m, x, s, e, T; + cin >> n >> m >> x; + vector> graph(n + 1, vector(0)); + while(m--){ + cin >> s >> e >> T; + graph[s].push_back({e, T}); + } + //연산 + vector dist_x = dijkstra(x, n, graph); //최단 시간 저장 + + int max_T = 0; //최대 시간의 값 초기화 + for (int i = 1; i <= n; i++) { + vector dist_i = dijkstra(i, n, graph); // i -> X의의 최단 시간 + max_T = max(max_T, dist_x[i] + dist_i[x]); //max_T 갱신 + } + + //출력 + cout << max_T; + + 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/15685.cpp" "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\355\225\204\354\210\230/15685.cpp" new file mode 100644 index 00000000..1e2dda0e --- /dev/null +++ "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\355\225\204\354\210\230/15685.cpp" @@ -0,0 +1,73 @@ +#include +#include + +using namespace std; + +const int SIZE = 100; + +// 방향: 우(0), 상(1), 좌(2), 하(3) +int dy[4] = { 0, -1, 0, 1 }; // 상, 하 +int dx[4] = { 1, 0, -1, 0 }; // 좌, 우 + +// 1x1 정사각형 개수 계산 +int cntSquares(vector>& plane) { + int ans = 0; // ans 초기화 + for (int i = 0; i < SIZE; i++) { + for (int j = 0; j < SIZE; j++) { + if (plane[i][j] && plane[i + 1][j] && plane[i][j + 1] && plane[i + 1][j + 1]) { + // 이웃한 네 개의 정사각형의 꼭짓점이 모두 1이면 + ans++; + } // ans 증가시킴 + } + } + return ans; // ans 반환 +} + +// 평면에 드래곤 커브를 표시 +void drawDragonCurve(vector>& plane, int x, int y, int d, int g) { + vector direct; // 방향 저장 + plane[y][x] = plane[y + dy[d]][x + dx[d]] = true; // 평면에 표시 (초기화) + x += dx[d]; // x 좌표 업데이트 + y += dy[d]; // y 좌표 업데이트 + direct.push_back(d); + while (g--) { // 1 ~ g 세대 반복 + int size_d = direct.size(); + for (int j = size_d - 1; j >= 0; j--) { // 방향의 계산 + int next_d = (direct[j] + 1) % 4; // 오른쪽으로 90도 회전해 다음 방향 계산 + x += dx[next_d]; // 다음 x 좌표 업데이트 + y += dy[next_d]; // 다음 y 좌표 업데이트 + plane[y][x] = true; // 평면에 표시 + direct.push_back(next_d); // 다음 세대의 방향 저장 + } + } +} + +/* +* 규칙 +* 0 세대: 0 +* 1 세대: 0 1 +* 2 세대: 0 1 2 1 +* 3 세대: 0 1 2 1 2 3 2 1 +* ... +* N 세대: concat((N-1세대), ((N-1세대 거꾸로) + 1)%4) +* 평면(좌측 상단이 (0, 0))에 드래곤 커브를 그린 후 정사각형의 개수를 계산 +* 드래곤 커브는 평면 밖으로 나가지 않음으로 범위를 확인할 필요 없음 +* 1. 0 세대의 드래곤 커브를 먼저 저장 (초기 조건) +* 2. 세대를 거듭하면서 드래곤 커브를 그림 (규칙을 파악하는 것이 중요) +* 3. 드래곤 커브가 그려진 평면 상의 정사각형의 개수 계산 (네 꼭짓점 확인) +*/ + +int main() +{ + int n, x, y, d, g; + vector> plane(SIZE + 1, vector(SIZE + 1, false)); // 평면 + // 입력 + cin >> n; + // 연산 & 출력 + while (n--) { // n개의 드래곤 커브 그리기 + cin >> x >> y >> d >> g; + drawDragonCurve(plane, x, y, d, g); + } + cout << cntSquares(plane) << '\n'; // 평면의 정사각형 개수 출력 + return 0; +} 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..1eb8b28c --- /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,58 @@ +#include +#include +#include +using namespace std; +const int INF = 1e9; + +//플로이드-워셜을 통해 각 점에서 다른 점으로 갈 수 있는지 확인 +void floydWarshall(int n, vector> &graph) { + for (int k = 1; k <= n; k++) { //중간 정점 + for (int i = 1; i <= n; i++) { //출발 정점 + for (int j = 1; j <= n; j++) { //도착 정점 + //중간에 k를 거쳐서 i에서 j로 갈 때 + int temp = graph[i][k] + graph[k][j]; + graph[i][j] = min(graph[i][j], temp); + } + } + } +} + +int main() +{ + ios_base::sync_with_stdio(false); + cin.tie(NULL), cout.tie(NULL); + //입력 + int N, M, a, b; + cin >> N >> M; + vector> graph(N + 1, vector(N + 1, INF)); + for (int i = 1; i <= N; i++) { //자기 자신과의 거리 + graph[i][i] = 0; + } + while(M--){ + cin >> a >> b; //a가 작은쪽, b가 큰쪽 + graph[a][b] = 1; //간선이 존재함 + } + + //연산 + floydWarshall(N, graph); + + //출력 + int ans = 0; + for(int i=1; i<=N; i++){ + bool flag = true; + for(int j=1; j<=N; j++){ + if(i == j) continue; + else if(graph[i][j] == INF && graph[j][i] == INF){ + flag = false; //i와 j 사이의 가중치가 없는 경우 + break; + } + } + if(flag) { + ans++; + } + + } + cout << ans; + + return 0; +} \ No newline at end of file diff --git a/README.md b/README.md index f6aae660..15359915 100644 --- a/README.md +++ b/README.md @@ -27,10 +27,10 @@ SW학부 원스탑 튜터링에서 진행하는 코딩 테스트 대비 알고 | 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) | [바로가기](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) | [바로가기]() | [바로가기]() | 녹화 강의 제공 | -| 2023.05.12 | 투 포인터 | [@kwakrhkr59](https://github.com/kwakrhkr59) | [바로가기]() | [바로가기]() | - | -| 2023.05.19 | 트리 | [@dbswn](https://github.com/dbswn) | [바로가기]() | [바로가기]() | - | -| 2023.05.26 | 최단 경로 | [@Dong-droid](https://github.com/Dong-droid) | [바로가기]() | [바로가기]() | - | +| 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) | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/12_%ED%8A%B8%EB%A6%AC/%EA%B0%95%EC%9D%98%20%EC%9E%90%EB%A3%8C/12_%ED%8A%B8%EB%A6%AC_%EC%9D%B4%EB%A1%A0.pdf) | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/tree/main/12_%ED%8A%B8%EB%A6%AC) | - | +| 2023.05.26 | 최단 경로 | [@Dong-droid](https://github.com/Dong-droid) | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/blob/main/13_%EC%B5%9C%EB%8B%A8%20%EA%B2%BD%EB%A1%9C/%EA%B0%95%EC%9D%98%20%EC%9E%90%EB%A3%8C/13_%EC%B5%9C%EB%8B%A8%EA%B2%BD%EB%A1%9C_%EC%9D%B4%EB%A1%A0.pdf) | [바로가기](https://github.com/Altu-Bitu-Official/Altu-Bitu-4/tree/main/13_%EC%B5%9C%EB%8B%A8%20%EA%B2%BD%EB%A1%9C) | - | | 2023.06.02 | 유니온 파인드 | [@bsa0322](https://github.com/bsa0322) | [바로가기]() | [바로가기]() | 2기 자료 제공 | | 2023.06.02 | 최소 신장 트리 | [@ZERO-black](https://github.com/ZERO-black) | [바로가기]() | [바로가기]() | 2기 자료 제공 | | 2023.06.02 | 위상 정렬 | [@bsa0322](https://github.com/bsa0322) | [바로가기]() | [바로가기]() | 2기 자료 제공 |