From e0c3f9f3307f813723df71367ac9c09bcefe2ac6 Mon Sep 17 00:00:00 2001 From: Esther Yoo Date: Tue, 4 Apr 2023 13:36:59 +0900 Subject: [PATCH 1/3] [DFS & BFS] 0404 --- .../\353\217\204\354\240\204/1844.cpp" | 45 +++++++++ .../\353\217\204\354\240\204/19538.cpp" | 93 +++++++++++++++++++ .../\355\225\204\354\210\230/1325.cpp" | 75 +++++++++++++++ .../\355\225\204\354\210\230/2615.cpp" | 64 +++++++++++++ .../\355\225\204\354\210\230/4963.cpp" | 85 +++++++++++++++++ 5 files changed, 362 insertions(+) create mode 100644 "08_DFS & BFS/\353\217\204\354\240\204/1844.cpp" create mode 100644 "08_DFS & BFS/\353\217\204\354\240\204/19538.cpp" create mode 100644 "08_DFS & BFS/\355\225\204\354\210\230/1325.cpp" create mode 100644 "08_DFS & BFS/\355\225\204\354\210\230/2615.cpp" create mode 100644 "08_DFS & BFS/\355\225\204\354\210\230/4963.cpp" diff --git "a/08_DFS & BFS/\353\217\204\354\240\204/1844.cpp" "b/08_DFS & BFS/\353\217\204\354\240\204/1844.cpp" new file mode 100644 index 00000000..b8482dca --- /dev/null +++ "b/08_DFS & BFS/\353\217\204\354\240\204/1844.cpp" @@ -0,0 +1,45 @@ +#include +#include +#include +using namespace std; +typedef pair pi; +// +int solution(vector> maps) +{ + int answer = 0; + int dr[] = {-1, 0, 1, 0}; + int dc[] = {0, 1, 0, -1}; + int n = maps.size(); + int m = maps[0].size(); + + // 시작점 0,0에서 BFS 실행 + queue q; + q.push({0, 0}); + while (!q.empty()) + { + int r = q.front().first; + int c = q.front().second; + q.pop(); + + for (int k = 0; k < 4; k++) + { + int nr = r + dr[k]; + int nc = c + dc[k]; + if (nr < n && nr >= 0 && nc < m && nc >= 0 && maps[nr][nc] == 1) + { + maps[nr][nc] = maps[r][c] + 1; + q.push({nr, nc}); + } + } + } + + if (maps[n - 1][m - 1] == 1) + { + answer = -1; + } + else + { + answer = maps[n - 1][m - 1]; + } + return answer; +} \ No newline at end of file diff --git "a/08_DFS & BFS/\353\217\204\354\240\204/19538.cpp" "b/08_DFS & BFS/\353\217\204\354\240\204/19538.cpp" new file mode 100644 index 00000000..fe07614a --- /dev/null +++ "b/08_DFS & BFS/\353\217\204\354\240\204/19538.cpp" @@ -0,0 +1,93 @@ +#include +#include +#include + +using namespace std; + +// BFS +vector tookMin(vector &rumor_mongers, int n, vector> &nbr_graph) +{ + int cnt = 0; + queue gossip; + queue influenced; + + // 모두 처음에는 안 믿는다. + vector believed(n + 1, -1); + vector cnt_nbr_believers(n + 1, 0); + + // 유포자를 큐에 넣는다 (0으로 셋팅) + for (int rm : rumor_mongers) + { + believed[rm] = 0; + gossip.push(rm); + } + + // 루머 유포 시작 + while (!gossip.empty()) + { + cnt++; + int node = gossip.front(); + gossip.pop(); + + for (int j = 0; j < nbr_graph[node].size(); j++) + { + int next_node = nbr_graph[node][j]; + // 안 믿는 사람이지만, 여론에 따라 믿게 되는 경우 + if (believed[next_node] == -1 && ++cnt_nbr_believers[next_node] >= (nbr_graph[next_node].size() + 1) / 2) + { + influenced.push(next_node); + gossip.push(next_node); + } + } + + // node에 의해 영향 받은 사람들이 동시에 믿게 된다. + while (!influenced.empty()) + { + believed[influenced.front()] = believed[node] + 1; + influenced.pop(); + } + } + cout << cnt << "*\n"; + return believed; +} + +int main() +{ + ios_base::sync_with_stdio(false); + cin.tie(NULL); + cout.tie(NULL); + + // 입력 + int n, m, nbr, rumor_monger; + cin >> n; + vector> nbr_graph(n + 1); + vector rumor_mongers; + + for (int i = 1; i <= n; i++) + { + while (true) + { + cin >> nbr; + if (!nbr) + { + break; + } + nbr_graph[i].push_back(nbr); + } + } + cin >> m; + while (m--) + { + cin >> rumor_monger; + rumor_mongers.push_back(rumor_monger); + } + + // 계산 + vector ans = tookMin(rumor_mongers, n, nbr_graph); + + // 출력 + for (int i = 1; i <= n; i++) + { + cout << ans[i] << ' '; + } +} \ No newline at end of file diff --git "a/08_DFS & BFS/\355\225\204\354\210\230/1325.cpp" "b/08_DFS & BFS/\355\225\204\354\210\230/1325.cpp" new file mode 100644 index 00000000..75e07821 --- /dev/null +++ "b/08_DFS & BFS/\355\225\204\354\210\230/1325.cpp" @@ -0,0 +1,75 @@ +#include +#include +#include + +using namespace std; + +vector mostEfficientHack(vector> &relate, int n) +{ + vector ans; + int max_cnt = 0; + + // 1부터 n번 컴퓨터까지 다 시작해본다. (브루트 포스) + for (int i = 1; i <= n; i++) + { + stack s; + vector visited(n + 1, false); + + s.push(i); + visited[i] = true; + int cnt = 1; + while (!s.empty()) + { + int node = s.top(); + s.pop(); + + for (int j = 0; j < relate[node].size(); j++) + { + int next_node = relate[node][j]; + if (!visited[next_node]) + { + // 해킹된 컴퓨터 있을때마다 count + visited[next_node] = true; + cnt++; + s.push(next_node); + } + } + } + // 최종 cnt로 max 업데이트 및 새로운 list + if (cnt > max_cnt) + { + max_cnt = cnt; + ans.resize(0); + ans.push_back(i); + } + else if (cnt == max_cnt) + { + ans.push_back(i); + } + } + return ans; +} + +int main() +{ + ios_base::sync_with_stdio(false); + cin.tie(NULL); + cout.tie(NULL); + + int n, m, a, b; + cin >> n >> m; + vector> relate(n + 1); + + while (m--) + { + cin >> a >> b; + relate[b].push_back(a); + } + + vector ans = mostEfficientHack(relate, n); + + for (int comp : ans) + { + cout << comp << ' '; + } +} \ No newline at end of file diff --git "a/08_DFS & BFS/\355\225\204\354\210\230/2615.cpp" "b/08_DFS & BFS/\355\225\204\354\210\230/2615.cpp" new file mode 100644 index 00000000..20e1222e --- /dev/null +++ "b/08_DFS & BFS/\355\225\204\354\210\230/2615.cpp" @@ -0,0 +1,64 @@ +#include +#include + +using namespace std; + +vector> board(19, vector(19, 0)); +int dr[] = {1, 1, 1, 0, 0, -1, -1, -1}; +int dc[] = {-1, 0, 1, -1, 1, -1, 0, 1}; + +// 같은 방향으로 계속 전진하다가 다른 숫자 만나면 or 바둑판 범위 넘어가면 depth 리턴 +int inARow(int i, int d, int r, int c, int color) +{ + if (r < 0 || r >= 19 || c < 0 || c >= 19 || board[r][c] != color) + { + return d; + } + + int nr = r + dr[i]; + int nc = c + dc[i]; + + return inARow(i, d + 1, nr, nc, color); +} + +int main() +{ + + for (int r = 0; r < 19; r++) + { + for (int c = 0; c < 19; c++) + { + cin >> board[r][c]; + } + } + + for (int r = 0; r < 19; r++) + { + for (int c = 0; c < 19; c++) + { + if (!board[r][c]) + { + continue; + } + + for (int i = 0; i < 8; i++) + { + // 리턴했을때 연속depth가 5였으면 승리!! //양방향 고려해줌 //양방향이므로 교집합 하나 빼줌 + if (5 == inARow(i, 0, r, c, board[r][c]) + inARow(7 - i, 0, r, c, board[r][c]) - 1) + { + // 밑에서 왼쪽 방향으로 가는 경우에만 시작점이 최대왼쪽이 아니라서, 업데이트해줘야함 + if (i == 0) + { + r += 4; + c -= 4; + } + cout << board[r][c] << '\n'; + cout << r + 1 << ' ' << c + 1; + return 0; + } + } + } + } + + cout << '0'; +} \ No newline at end of file diff --git "a/08_DFS & BFS/\355\225\204\354\210\230/4963.cpp" "b/08_DFS & BFS/\355\225\204\354\210\230/4963.cpp" new file mode 100644 index 00000000..098cf6f0 --- /dev/null +++ "b/08_DFS & BFS/\355\225\204\354\210\230/4963.cpp" @@ -0,0 +1,85 @@ +#include +#include +#include + +using namespace std; + +typedef pair pi; +int dr[] = {-1, -1, -1, 0, 0, 1, 1, 1}; +int dc[] = {-1, 0, 1, -1, 1, -1, 0, 1}; + +// bfs를 통한 섬 개수 세기 + +int cntIsland(vector> &map, int h, int w) +{ + // 미개척 땅이 1이므로 2부터 셈 + int cnt = 1; + queue ut; + + // cout << "^__^"; + + for (int i = 0; i < h; i++) + { + for (int j = 0; j < w; j++) + { + // 개척 안한 땅 발견하면 "새 섬이다!" + if (map[i][j] == 1) + { + cnt++; + map[i][j] = cnt; + ut.push({i, j}); + + // 해당 섬 끝까지 마킹 + while (!ut.empty()) + { + pi land = ut.front(); + ut.pop(); + + for (int k = 0; k < 8; k++) + { + int nr = land.first + dr[k]; + int nc = land.second + dc[k]; + + if (nr >= 0 && nr < h && nc >= 0 && nc < w && map[nr][nc] == 1) + { + map[nr][nc] = cnt; + ut.push({nr, nc}); + } + } + } + + } + } + } + return --cnt; +} + +int main() +{ + ios_base::sync_with_stdio(false); + cin.tie(NULL); + cout.tie(NULL); + + int w, h; + + while (true) + { + cin >> w >> h; + if (!w && !h) + { + break; + } + + vector> map(h, vector(w, 0)); + + for (int i = 0; i < h; i++) + { + for (int j = 0; j < w; j++) + { + cin >> map[i][j]; + } + } + + cout << cntIsland(map, h, w) << '\n'; + } +} \ No newline at end of file From 1a78dabe66a9283993547b29c215e96b163f6b0f Mon Sep 17 00:00:00 2001 From: Esther Yoo Date: Thu, 18 May 2023 23:00:51 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[=ED=88=AC=ED=8F=AC=EC=9D=B8=ED=84=B0]=2005?= =?UTF-8?q?18?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../\355\225\204\354\210\230/14503.cpp" | 93 +++++++++++++++++ .../\355\225\204\354\210\230/14503_.cpp" | 99 +++++++++++++++++++ .../\355\225\204\354\210\230/20437_.cpp" | 79 +++++++++++++++ .../\355\225\204\354\210\230/20922_.cpp" | 58 +++++++++++ 4 files changed, 329 insertions(+) create mode 100644 "11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/14503.cpp" create mode 100644 "11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/14503_.cpp" create mode 100644 "11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/20437_.cpp" create mode 100644 "11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/20922_.cpp" diff --git "a/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/14503.cpp" "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/14503.cpp" new file mode 100644 index 00000000..925432a7 --- /dev/null +++ "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/14503.cpp" @@ -0,0 +1,93 @@ +#include +#include + +using namespace std; + +int dr[] = {-1, 0, 1, 0}; +int dc[] = {0, 1, 0, -1}; + +int cleaned(vector> &room, int r, int c, int d) +{ + // robot's current position + int cur_r = r; + int cur_c = c; + int cur_d = d; + int isDirty; + int cnt = 0; + int b; + + while (true) + { + // 주변에 더러운 빈칸이 없다. + isDirty = -1; + + // 1. 현재 칸이 청소되지 않은 경우, 현재 칸을 청소한다. + if (!room[cur_r][cur_c]) + { + room[cur_r][cur_c] = -1; + cnt++; + } + + // 주변 4칸 중 청소되지 않은 빈칸이 있는가? + for (int i = 0; i < 4; i++) + { + if (!room[cur_r + dr[i]][cur_c + dc[i]]) + { + isDirty = i; + break; + } + } + + // 2. 현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 없는 경우, + if (isDirty == -1) + { + // 2-1. 바라보는 방향을 유지한 채로 한 칸 후진할 수 있다면 한 칸 후진하고 1번으로 돌아간다. + b = (cur_d + 2) % 4; + if (room[cur_r + dr[b]][cur_c + dc[b]] != 1) + { + cur_r += dr[b]; + cur_c += dc[b]; + continue; + } + else + { + // 2-2. 바라보는 방향의 뒤쪽 칸이 벽이라 후진할 수 없다면 작동을 멈춘다. + break; + } + } + + // 3. 현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 있는 경우, + else + { + //3-1. 반시계 방향으로 90도 회전한다. + cur_d = (cur_d +3) % 4; + //3-2. 바라보는 방향을 기준으로 앞쪽 칸이 청소되지 않은 빈 칸인 경우 한 칸 전진한다. + if (!room[cur_r + dr[cur_d]][cur_c + dc[cur_d]]) + { + cur_r += dr[cur_d]; + cur_c += dc[cur_d]; + } + //3-3. 1번으로 돌아간다. + } + } + + return cnt; +} + +int main() +{ + int n, m, r, c, d; + cin >> n >> m >> r >> c >> d; + vector> room(n, vector(m, 0)); + + + for (int i = 0; i < n; i++) + { + for (int j = 0; j < m; j++) + { + cin >> room[i][j]; + } + } + + cout << cleaned(room, r, c, d); +} \ 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_.cpp" "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/14503_.cpp" new file mode 100644 index 00000000..563957b6 --- /dev/null +++ "b/11_\355\210\254 \355\217\254\354\235\270\355\204\260/\355\225\204\354\210\230/14503_.cpp" @@ -0,0 +1,99 @@ +#include +#include + +// 내 코드와 비교하며 배울 점 : +// 문제를 자연스러운 흐름으로 재구성함. 청소되지 않은 빈칸이 있는가? 있다면 바로 3번 시행. +// 가독성 좋은 변수명을 활용함. int isDirty -> bool find, cur_r -> row, +// 불필요한 변수 할당을 최소화함. row, col 등등. +// if와 else문이 있을때, else문을 쓰지 않아도 된다면 쓰지 않는다. +// 중간 단계 (nr, nc, nd)를 둠으로써 while문이 도는 경우를 줄였다. 대신 메모리도 그만큼 조금 늘어난듯? + +using namespace std; + +const int CLEAN = 2; // 확실히 '깨끗하다' 처럼 긍정적인 의미일경우 -1 대신 2 같은 positive number를 쓰는게 나은 거 같다. + +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; // 현재 칸을 청소한다. 이건 근데 위 if문 안에 넣어도 될 것 같은데. + + bool find = false; // 현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 있는가 + for (int i = 0; i < 4; i++) // 주변 4칸 탐색 + { + int nd = (d - i + 3) % 4; // 3-1. 반시계 방향으로 90도 회전 (임의로) + int nr = r + dy[nd], nc = c + dx[nd]; // 3-2. 바라보는 방향을 기준으로 앞쪽 칸이 + + if (board[nr][nc] == 0) + { // 3-2. 아직 청소되지 않은 첫 빈 칸임을 + find = true; // 발견하여 + r = nr; // 전! + c = nc; // 진! + d = nd; // 완전히 회전한다. + break; // 나머지 방향들은 볼 필요 없이 떠난다. + } + } + if (find) + { // 3-3. 현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 있는 경우 1번으로 돌아감 + continue; // 이 continue는 위의 for문 밖에서 써야 while문에 적용되기 때문에 굳이 find라는 flag 변수를 만들어줘야함. + } + + // 2. 현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 없는 경우 + int bd = (d + 2) % 4; // 북남, 동서는 2 차이씩 나기 때문에 backward direction은 + int br = r + dy[bd], bc = c + dx[bd]; // 이런식으로 임의로 정함. + + // [바라보는 방향을 유지한 채로 한 칸 후진할 수 있는가] + // 2-2. 뒤쪽 칸이 벽이라 후진할 수 없는 경우 + if (board[br][bc] == 1) + { + return cnt; // 바로 끝낸다. break를 사용해도 좋다. + } + // 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; // 청소할 room + + // 입력 + cin >> n >> m; + cin >> r >> c >> d; + board.assign(n, vector(m, 0)); // 이때 n, m 대신 n, n 을 쓰게되면 invalid next 런타임 에러가 난다. + for (int i = 0; i < n; i++) + { + for (int j = 0; j < m; j++) // m 인거 조심하자. + { + 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..32f65bb8 --- /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,79 @@ +#include +#include +#include + +// 추가제출 +// 배울점 : +// - 예외처리 if else로 깔끔하게 함 +// - 슬라이딩 윈도우 적용하여 2가지 요구사항을 한번에 해결함. +// - 알파벳 별로 구현함. +// 알파벳별로 인덱스를 모아주고, 그 안에서 윈도우를 이동시킴!!! +// 꼭 주어진 STRING 내부에서 포인터를 사용할 필요가 없다. 필요에 따라 적절히 인풋을 재구성해야한다. + +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; // 가장 긴 문자열 길이 초기화(이후 예외처리를 위해 -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()) // K개 이상 있는 애들에 관하여. + { + 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..87df02b2 --- /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,58 @@ +#include +#include +#include + +// 추가제출 +// 내 코드랑 다른점: +// - 나는 for문으로 right를 옮기려 했고, 여기서는 while문을 씀. +// 중간에 left 움직였다가 right 움직였다가 계속 왔다갔다 하기 때문에 for문 내 i라는 딱 하나의 인덱스를 고정하는건 비효율적임을 배움. +// - 굳이 map 라이브러리 안 써도 count 벡터로 숫자 세기 가능. + +using namespace std; +const int MAX_NUM = 100001; // 수열 내 숫자 최대값 + +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 포인터를 0에서부터 끝까지 계속 옮김 + { + // 인덱스를 옮겨가면서 해당 숫자를 수열에 옮길 수 있을지 판단 + if (count[number[right]] >= k) + { // 해당 숫자의 개수가 k가 넘으면 추가 불가 + count[number[left]]--; // left 숫자를 더이상 고려하지 않고 + left++; // left 포인터를 옮김(아마 right까지 계속 가게 될것.) + } + 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 From 99d689383c6fca176397f62134a2053609e2021c Mon Sep 17 00:00:00 2001 From: Esther Yoo Date: Thu, 25 May 2023 23:27:55 +0900 Subject: [PATCH 3/3] =?UTF-8?q?[=ED=8A=B8=EB=A6=AC]=200525?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../\355\225\204\354\210\230/15681.cpp" | 65 ++++++++++++ .../\355\225\204\354\210\230/3190.cpp" | 100 ++++++++++++++++++ .../\355\225\204\354\210\230/5639.cpp" | 59 +++++++++++ 3 files changed, 224 insertions(+) create mode 100644 "12_\355\212\270\353\246\254/\355\225\204\354\210\230/15681.cpp" create mode 100644 "12_\355\212\270\353\246\254/\355\225\204\354\210\230/3190.cpp" create mode 100644 "12_\355\212\270\353\246\254/\355\225\204\354\210\230/5639.cpp" 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..fbd9aa88 --- /dev/null +++ "b/12_\355\212\270\353\246\254/\355\225\204\354\210\230/15681.cpp" @@ -0,0 +1,65 @@ +#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; // 트리의 정점의 수 N과 루트의 번호 R, 쿼리의 수 Q + + vector> tree(n + 1, vector(0)); + + //edge 입력받음 + for (int i = 0; i < n - 1; i++) + { + cin >> u >> v; + tree[u].push_back(v); + tree[v].push_back(u); + } + + // 연산 + vector dp(n + 1, 1); // 자신도 자신을 루트로 하는 서브트리에 포함되므로 0이 아닌 1로 dp 초기값 설정 + dfs(r, 0, tree, dp); + + // 출력 + while (q--) + { + cin >> u; + cout << dp[u] << '\n'; + } +} \ No newline at end of file diff --git "a/12_\355\212\270\353\246\254/\355\225\204\354\210\230/3190.cpp" "b/12_\355\212\270\353\246\254/\355\225\204\354\210\230/3190.cpp" new file mode 100644 index 00000000..acf6e396 --- /dev/null +++ "b/12_\355\212\270\353\246\254/\355\225\204\354\210\230/3190.cpp" @@ -0,0 +1,100 @@ +#include +#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}; // 각각 x,y 방향 따로 + 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; // 뱀의 머리 x좌표 + y = snake.front().second; // 뱀의 머리 y좌표 + if (direction[time] != 0) // 뱀의 방향 변환 정보가 있으면 + { + dir = (dir + direction[time]) % 4; // 뱀의 방향 갱신 + } + time++; // 게임 시간 1초 추가 + nx = x + dx[dir]; // 임의의 뱀 머리의 x 좌표 + ny = y + dy[dir]; // 임의의 뱀 머리의 y 좌표 + + // 뱀의 머리가 벽에 부딪히거나 //자기 자신의 몸과 충돌하면 게임 종료 + 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 //'L' + { + 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..f7d4088e --- /dev/null +++ "b/12_\355\212\270\353\246\254/\355\225\204\354\210\230/5639.cpp" @@ -0,0 +1,59 @@ +#include +#include + +using namespace std; + +void postOrder(int left, int right, vector &tree) +{ + if (left > right) // 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