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 9d54f6c2..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" @@ -23,16 +23,16 @@ | 문제 번호 | 문제 이름 | 난이도 | 풀이 링크 | 분류 | | :-----------------------------------------------------------------------: | :------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :-------: | :------------------------: | -| 14503 | 로봇 청소기 | | [C++]() | 구현, 시뮬레이션 | -| 20922 | 겹치는 건 싫어 | | [C++]() | 투 포인터 | -| 20437 | 문자열 게임 2 | | [C++]() | 슬라이딩 윈도우 | +| 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++]() | 투 포인터, 슬라이딩 윈도우 | -| 2473 | 세 용액 | | [C++]() | 투 포인터 | +| 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) | 투 포인터 | --- ### 힌트 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/\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" index 442dc181..acb41859 100644 --- "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" @@ -1,3 +1,62 @@ + 1914039-13 +#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"; +======= #include #include #include @@ -51,7 +110,7 @@ int main() { cout << -1 << "\n"; } else { - cout << min_length << " " << max_length << "\n"; //문자열을 찾은 경우->출력 + } } return 0; 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" index 61aa096b..28daa3ba 100644 --- "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" @@ -1,3 +1,50 @@ + +#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; +======= #include #include #include @@ -38,4 +85,5 @@ int main() { cout << max_length; 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..e7333b20 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 | 최단경로 | | [바로가기](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/%EB%9D%BC%EC%9D%B4%EB%B8%8C%20%EC%BD%94%EB%94%A9/1753.cpp) | 다익스트라 | +| 11404 | 플로이드 | | [바로가기](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/%EB%9D%BC%EC%9D%B4%EB%B8%8C%20%EC%BD%94%EB%94%A9/11404.cpp) | 플로이드-워셜 | +| 11657 | 타임머신 | | [바로가기](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/%EB%9D%BC%EC%9D%B4%EB%B8%8C%20%EC%BD%94%EB%94%A9/11657.cpp) | 벨만-포드 | + +## ✏️ 과제 + +### 마감기한 + +~ 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..9178dc29 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/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/11404.cpp" "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/11404.cpp" new file mode 100644 index 00000000..b8d0b059 --- /dev/null +++ "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/11404.cpp" @@ -0,0 +1,46 @@ +#include +#include +#include + +using namespace std; +const int INF = 1e7; // 최대 n-1개의 간선을 지나므로 n * (가중치 최대값) + +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 cost = graph[i][k] + graph[k][j]; + // 더 짧은 경로 선택 + graph[i][j] = min(graph[i][j], cost); + } + } + } +} + +int main() { + int n, m, a, b, c; + + // 입력 + 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 >> c; + graph[a][b] = min(graph[a][b], c); // 비용 여러개일 수 있으므로 최솟값으로 + } + + // 연산 + floydWarshall(n, graph); + + // 출력 + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= n; j++) { + cout << (graph[i][j] == INF ? 0 : graph[i][j]) << ' '; + } + cout << '\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/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/11657.cpp" "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/11657.cpp" new file mode 100644 index 00000000..f9f5a8aa --- /dev/null +++ "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/11657.cpp" @@ -0,0 +1,63 @@ +#include +#include +#include + +using namespace std; +typedef pair ci; +const int INF = 2e5; // 최대 V-1개의 간선을 지나게 됨 -> V * (가중치 최대값) + +// 다익스트라 +vector dijkstra(int start, int v, vector> &graph) { + vector dist(v + 1, INF); // 각 정점까지의 최단 경로 저장 + // 현재 탐색하는 중간 정점까지의 최단 경로 + priority_queue, greater<>> pq; // first: 시작점으로부터의 거리, second: 정점 + + // 시작 정점 초기화 + dist[start] = 0; + pq.push({0, start}); + 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++) { + int next_node = graph[node][i].first; // 연결된 정점 + // 시작점으로부터 현재 node를 거쳐 다음 정점까지 가는 경로값 + int next_weight = weight + graph[node][i].second; + if (next_weight < dist[next_node]) { // 최단 경로 값이 갱신된다면 + dist[next_node] = next_weight; + pq.push({next_weight, next_node}); + } + } + } + return dist; +} + +int main() { + int v, e, k, a, b, w; + + // 입력 + cin >> v >> e >> k; + vector> graph(v + 1, vector(0)); // 인접 리스트 + while (e--) { + cin >> a >> b >> w; + graph[a].push_back({b, w}); // 방향 그래프 + } + + // 연산 + vector dist = dijkstra(k, v, graph); + + // 출력 + for (int i = 1; i <= v; i++) { + if (dist[i] == INF) { + cout << "INF"; + } else { + cout << dist[i]; + } + cout << '\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/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/1753.cpp" "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/1753.cpp" new file mode 100644 index 00000000..29aa6a14 --- /dev/null +++ "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\353\235\274\354\235\264\353\270\214 \354\275\224\353\224\251/1753.cpp" @@ -0,0 +1,63 @@ +#include +#include +#include + +using namespace std; +typedef pair ci; +const int INF = 2e5; // 최대 V-1개의 간선을 지나게 됨 -> V * (가중치 최대값) + +// 다익스트라 +vector dijkstra(int start, int v, vector> &graph) { + vector dist(v + 1, INF); //각 정점까지의 최단 경로 저장 + // 현재 탐색하는 중간 정점까지의 최단 경로 + priority_queue, greater<>> pq; // first: 시작점으로부터의 거리, second: 정점 + + // 시작 정점 초기화 + dist[start] = 0; + pq.push({0, start}); + 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++) { + int next_node = graph[node][i].first; // 연결된 정점 + // 시작점으로부터 현재 node를 거쳐 다음 정점까지 가는 경로값 + int next_weight = weight + graph[node][i].second; + if (next_weight < dist[next_node]) { // 최단 경로 값이 갱신된다면 + dist[next_node] = next_weight; + pq.push({next_weight, next_node}); + } + } + } + return dist; +} + +int main() { + int v, e, k, a, b, w; + + // 입력 + cin >> v >> e >> k; + vector> graph(v + 1, vector(0)); // 인접 리스트 + while (e--) { + cin >> a >> b >> w; + graph[a].push_back({b, w}); // 방향 그래프 + } + + // 연산 + vector dist = dijkstra(k, v, graph); + + // 출력 + for (int i = 1; i <= v; i++) { + if (dist[i] == INF) { + cout << "INF"; + } else { + cout << dist[i]; + } + cout << '\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/\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/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\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/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..92e36283 --- /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,89 @@ +#include +#include +#include +#include + +//단반향 도로이므로 가는길과 돌아오는 길을 구분함을 주의 +//따라서 걸리는 시간을 배열로 만들어 가장 큰 값을 출력 + +int inf= 987654321; +using namespace std; + +int n, m, x; +int dist[1010], res[1010]; +vector> v[1010];//간선의 정보 저장 + +void Input(){ + cin >> n >> m >> x; //초기 입력값 + + for (int i = 0; i < m; i++){ + int a, b, c; + cin >> a >> b >> c; + v[a].push_back(make_pair(b, c));//간선의 정보를 push + } +} + +void Dijkstra(int start){ + + priority_queue> PQ; + dist[start] = 0; + PQ.push(make_pair(0, start)); + + while (PQ.empty() == 0){ + + int cost = -PQ.top().first; + int cur = PQ.top().second; + PQ.pop(); //coast와 cur에 저장한 다음 pop + + if (cost > dist[cur]) {//탐색하려는 값이 기존 값 보다 크다면 탐색할 필요x->구하지 않고 넘어감 + continue; + } + + for (int i = 0; i < v[cur].size(); i++){ + int next = v[cur][i].first; + int nCost = v[cur][i].second; + + if (dist[next] > cost + nCost){//만약 더 크다면->최소값으로 갱신->pq에 저장 + dist[next] = cost + nCost; + PQ.push(make_pair(-dist[next], next)); + } + } + } + +} + +void Solution() { + + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= n; j++) { + dist[j] = inf; + } + Dijkstra(i); + res[i] = dist[x];//i에서 x까지 가는데 걸리는 시간을 구함->res[i]에 저장 + } + for (int j = 1; j <= n; j++) { + dist[j] = inf;//배열 다시 초기화 + } + + Dijkstra(x);// x에서 i까지 가는데 걸리는 시간 + for (int i = 1; i <= n; i++) { + res[i] = res[i] + dist[i];//총 소요 시간=가는데 걸리는 시간+오는데 걸리는 시간 (도로가 단방향이므로) + } + + sort(res + 1, res + n + 1);// 가장 큰 값을 찾기 위해 정렬 + int answer = res[n];//가장 큰 값 + + cout << answer; +} + +int main(){ + ios::sync_with_stdio(false); + cin.tie(NULL); + cout.tie(NULL); + + Input(); + Solution(); + + return 0; +} + diff --git "a/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\355\225\204\354\210\230/15685-\354\266\224\352\260\200\354\240\234\354\266\234.cpp" "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\355\225\204\354\210\230/15685-\354\266\224\352\260\200\354\240\234\354\266\234.cpp" new file mode 100644 index 00000000..6748759c --- /dev/null +++ "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\355\225\204\354\210\230/15685-\354\266\224\352\260\200\354\240\234\354\266\234.cpp" @@ -0,0 +1,72 @@ +#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; + 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]) { + ans++;// 좌표밖을 벗어나지 않는다면->ans 증가 + } + } + } + return 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]; + y += dy[d]; + 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도로 4, 8, 12... 회전하면 원위치이므로 %4를 해줌 + x += dx[next_d]; + y += dy[next_d]; + 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; +} \ 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-\354\266\224\352\260\200\354\240\234\354\266\234.cpp" "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\355\225\204\354\210\230/2458-\354\266\224\352\260\200\354\240\234\354\266\234.cpp" new file mode 100644 index 00000000..c1075d86 --- /dev/null +++ "b/13_\354\265\234\353\213\250 \352\262\275\353\241\234/\355\225\204\354\210\230/2458-\354\266\224\352\260\200\354\240\234\354\266\234.cpp" @@ -0,0 +1,66 @@ +#include +#include +#include + +using namespace std; +const int INF = 501; // 최대 n-1개의 간선을 지나므로 n * (가중치 최대값) + +void init(int n, vector>& graph) { + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= n; j++) { + graph[i][j] = INF;//최대값으로 초기화 + } + } + for (int i = 1; i <= n; i++) { + graph[i][i] = 0; //자기자신 가중치=0임으로 0으로 초기화 + } +} + +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 cost = graph[i][k] + graph[k][j]; + // 더 짧은 경로 선택 + graph[i][j] = min(graph[i][j], cost); + } + } + } +} + +int countStudents(int student, int n, vector>& graph) { + int i = 1, cnt = 0; + for (i = 1; i <= n; i++) { + if (student != i && graph[student][i] == INF && graph[i][student] == INF) { + return 0; + } + } + return 1; +} +/* + * 키순서 + * 내 키의 순위를 안다 <-> 내가 상대방과의 키 우열을 안다 or 상대방이 나와의 키 우열을 안다 +*/ +int main() +{ + int n, m; + int answer = 0; + vector> graph(INF, vector(INF)); + // 입력 + cin >> n >> m; + init(n, graph); // 초기화 + while (m--) { + int a, b; + cin >> a >> b; + graph[a][b] = 1; // 키 우열을 아는 두 정점의 거리를 1이라고 하자 + } + // 연산 + floydWarshall(n, graph); + for (int i = 1; i <= n; i++) { // 자신의 키가 몇 번째인지 알 수 있는 학생들이 몇 명인지 계산 + answer += countStudents(i, n, graph);//자기보다 작은 학생들이 있으면 1반환->학생수만큼 반복하면 카운트 + } + // 출력 + cout << answer << '\n'; + return 0; +} \ No newline at end of file diff --git a/README.md b/README.md index dbf4b4d4..15359915 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,8 @@ SW학부 원스탑 튜터링에서 진행하는 코딩 테스트 대비 알고 | 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.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기 자료 제공 |