diff --git "a/#17 0524_\354\234\240\353\213\210\354\230\250_\355\214\214\354\235\270\353\223\234/BOJ_1043_sample.cpp" "b/#17 0524_\354\234\240\353\213\210\354\230\250_\355\214\214\354\235\270\353\223\234/BOJ_1043_sample.cpp" new file mode 100644 index 0000000..88b1f6f --- /dev/null +++ "b/#17 0524_\354\234\240\353\213\210\354\230\250_\355\214\214\354\235\270\353\223\234/BOJ_1043_sample.cpp" @@ -0,0 +1,89 @@ +/* 거짓말 : sample */ + +#include +#include + +using namespace std; + +vector parent; + +//Find 연산 +int findParent(int node) { + if (parent[node] < 0) { + return node; + } + return parent[node] = findParent(parent[node]); +} + +//Union 연산 +void unionInput(int x, int y) { + int xp = findParent(x); + int yp = findParent(y); + + if (xp == yp) { + return; + } + if (parent[xp] < parent[yp]) { + parent[xp] += parent[yp]; + parent[yp] = xp; + } else { + parent[yp] += parent[xp]; + parent[xp] = yp; + } +} + +int liarParty(vector &parties) { + int cnt = 0; + for (int i = 0; i < parties.size(); i++) { + if (findParent(parties[i]) != findParent(0)) { + cnt++; + } + } + return cnt; +} + +/** + * [거짓말] + * + * 1. 각 사람들은 다양한 파티를 통해 연결됐다고 할 수 있음 + * 2. 연결된 사람들은 같은 집합에 속함 + * 3. 각 집합에 속한 사람들 중 한 명이라도 진실을 안다면 그 집합의 사람들이 속한 파티에는 거짓말을 할 수 없음 + * -> 유니온 파인드로 사람들을 집합으로 묶은 뒤, 파티마다 거짓말을 할 수 있는지 확인하기 + * -> 이때, 진실을 아는 사람들의 루트 정점을 0으로 설정해서 유니온 파인드를 통해 집합으로 묶고 시작 + * -> 0과 같은 집합이 아니어야 거짓말을 할 수 있음 + * + * !주의! 파티 정보를 입력받으며 바로 거짓말 가능 여부를 판단할 수 없음 (예제 입력 4) + * 각 파티에서 한 사람만 저장해둔 뒤, 마지막에 거짓말 가능 여부 한 번에 판단 + */ + +int main() { + int n, m; + + //입력 + cin >> n >> m; + parent.assign(n + 1, -1); + + int init, p; + cin >> init; + while (init--) { //진실을 아는 사람들 + cin >> p; + unionInput(0, p); + } + + int cnt, first_person, person; + vector parties; + while (m--) { + cin >> cnt >> first_person; + + //연산 + parties.push_back(first_person); //파티 정보로 각 파티의 첫번째 사람만 저장 + while (--cnt) { + cin >> person; + unionInput(first_person, person); + } + } + + //연산 & 출력 + cout << liarParty(parties); + return 0; +} \ No newline at end of file diff --git "a/#17 0524_\354\234\240\353\213\210\354\230\250_\355\214\214\354\235\270\353\223\234/BOJ_12100_sample.cpp" "b/#17 0524_\354\234\240\353\213\210\354\230\250_\355\214\214\354\235\270\353\223\234/BOJ_12100_sample.cpp" new file mode 100644 index 0000000..b77e873 --- /dev/null +++ "b/#17 0524_\354\234\240\353\213\210\354\230\250_\355\214\214\354\235\270\353\223\234/BOJ_12100_sample.cpp" @@ -0,0 +1,124 @@ +/* 2048 : sample */ + +#include +#include +#include + +using namespace std; +typedef vector> matrix; + +int n, ans = 0; + +int getMaxBlock(matrix &board) { + int max_block = 0; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + max_block = max(max_block, board[i][j]); + } + } + return max_block; +} + +matrix transposeMatrix(matrix &board) { + matrix board_t(n, vector(n, 0)); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + board_t[i][j] = board[j][i]; + } + } + return board_t; +} + +/** + * 상으로 이동하는 함수 + * - 한 열씩 검사하면서 위의 행부터 2개씩 같은 거 있다면 합치기 + * - 이때 블록 없는 부분은 넘어가고, 블록이 존재했던 값을 저장해서 비교하는 것이 중요! + */ +matrix upMove(matrix board) { + matrix temp(n, vector(n, 0)); //새롭게 블록 저장할 배열 + for (int j = 0; j < n; j++) { + int idx = 0; + int prev = 0; + for (int i = 0; i < n; i++) { + if (!board[i][j]) { + continue; + } + if (board[i][j] == prev) { + temp[idx - 1][j] *= 2; + prev = 0; + } else { + temp[idx++][j] = board[i][j]; + prev = board[i][j]; + } + } + } + return temp; +} + +//백트래킹 탐색 +void backtracking(int cnt, matrix board) { + if (cnt == 5) { + ans = max(ans, getMaxBlock(board)); + return; + } + //Transpose matrix 구하기 (상->좌) + matrix board_t = transposeMatrix(board); + //상 + backtracking(cnt + 1, upMove(board)); + //하 + reverse(board.begin(), board.end()); + backtracking(cnt + 1, upMove(board)); + //좌 + backtracking(cnt + 1, upMove(board_t)); + //우 + reverse(board_t.begin(), board_t.end()); + backtracking(cnt + 1, upMove(board_t)); +} + +/** + * [2048 (Easy)] + * + * - 상, 하, 좌, 우로 이동하는 경우에 대해 최대 5번 이동시키는 모든 경우를 구한 후, 가장 큰 블록 찾는 문제 - 백트래킹 + * - 움직이는 함수는 하나만 짜고, 보드를 돌려가면서 상, 하, 좌, 우 모든 방향의 움직임을 만듦 + * + * - 상 <-> 하: 행 순서를 뒤집어서 해결 + * - 상/하 <-> 좌/우: Transpose Matrix 활용 + * + * - ex. 2 2 1 를 상, 하, 좌, 우로 이동하는 경우 구하는 법 + * 2 2 2 + * 4 4 4 + * -상: 원래 배열에서 상으로 움직이는 함수 실행 + * 2 2 1 4 4 1 + * 2 2 2 -> 4 4 2 + * 4 4 4 0 0 4 + * -하: 원래 배열의 행 순서를 뒤집은 후, 상으로 움직이는 함수 실행 + * 2 2 1 4 4 4 4 4 4 + * 2 2 2 -> 2 2 2 -> 4 4 2 + * 4 4 4 2 2 1 0 0 1 + * -좌: 원래 배열의 전치 행렬을 구한 후, 상으로 움직이는 함수 실행 + * 2 2 1 2 2 4 4 4 8 + * 2 2 2 -> 2 2 4 -> 1 2 4 + * 4 4 4 1 2 4 0 0 0 + * -우: 원래 배열의 전치 행렬에서 행 순서를 뒤집은 후, 상으로 움직이는 함수 실행 + * 2 2 1 1 2 4 1 4 8 + * 2 2 2 -> 2 2 4 -> 4 2 4 + * 4 4 4 2 2 4 0 0 0 + */ + +int main() { + //입력 + cin >> n; + matrix board(n, vector(n, 0)); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + cin >> board[i][j]; + } + } + + //연산 + backtracking(0, board); + + //출력 + cout << ans; + return 0; +} \ No newline at end of file diff --git "a/#17 0524_\354\234\240\353\213\210\354\230\250_\355\214\214\354\235\270\353\223\234/BOJ_16114_sample.cpp" "b/#17 0524_\354\234\240\353\213\210\354\230\250_\355\214\214\354\235\270\353\223\234/BOJ_16114_sample.cpp" new file mode 100644 index 0000000..46a5d0f --- /dev/null +++ "b/#17 0524_\354\234\240\353\213\210\354\230\250_\355\214\214\354\235\270\353\223\234/BOJ_16114_sample.cpp" @@ -0,0 +1,43 @@ +/* 화살표 연산자 : sample */ + +#include + +using namespace std; + +string solution(int x, int n) { + if (n > 1 && n % 2 == 1) { + return "ERROR"; + } + if (n == 1 && x < 0) { + return "INFINITE"; + } + if (n == 1 || x <= 0) { + return "0"; + } + if (n == 0) { + return "INFINITE"; + } + return to_string((x - 1) / (n / 2)); +} + +/** + * [화살표 연산자] + * + * 1. n이 1보다 큰 홀수인 경우 -> ERROR + * 2. n이 1인데 x가 음수인 경우 -> while문 조건 항상 참 -> INFINITE + * 3. n이 1인데 x가 양수인 경우 or x가 0보다 작거나 같은 경우 -> while문에 진입 못함 -> 0 + * 4. n이 0인데 x가 양수인 경우 -> while문 조건 항상 참 -> INFINITE + * 5. 나머지 경우엔 (x - 1)을 (n / 2)로 나눈 몫을 출력 + * - 연산했을 때 1 이상이 남을 때까지만 출력을 할 수 있으므로 1을 뺀 값에서 몫을 구함 + */ + +int main() { + int x, n; + + //입력 + cin >> x >> n; + + //연산 & 출력 + cout << solution(x, n); + return 0; +} \ No newline at end of file diff --git "a/#17 0524_\354\234\240\353\213\210\354\230\250_\355\214\214\354\235\270\353\223\234/BOJ_20040_sample.cpp" "b/#17 0524_\354\234\240\353\213\210\354\230\250_\355\214\214\354\235\270\353\223\234/BOJ_20040_sample.cpp" new file mode 100644 index 0000000..0cbce4a --- /dev/null +++ "b/#17 0524_\354\234\240\353\213\210\354\230\250_\355\214\214\354\235\270\353\223\234/BOJ_20040_sample.cpp" @@ -0,0 +1,60 @@ +/* 사이클 게임 : sample */ + +#include +#include + +using namespace std; + +vector parent; + +//Find 연산 +int findParent(int node) { + if (parent[node] < 0) { + return node; + } + return parent[node] = findParent(parent[node]); +} + +//Union 연산 +bool unionInput(int x, int y) { + int xp = findParent(x); + int yp = findParent(y); + + if (xp == yp) { + return false; + } + if (parent[xp] < parent[yp]) { + parent[xp] += parent[yp]; + parent[yp] = xp; + } else { + parent[yp] += parent[xp]; + parent[xp] = yp; + } + return true; +} + +/** + * [사이클 게임] + * + * 사이클이 발생한 순간 = 같은 집합에 있는 원소 두 개를 유니온하려 할 때 + * unionInput 함수의 반환형을 bool로 선언하여 cycle이 생성되는 순간 발견하기 + */ + +int main() { + int n, m, x, y; + + //입력 + cin >> n >> m; + parent.assign(n, -1); + for (int i = 0; i < m; i++) { + cin >> x >> y; + + //연산 & 출력 + if (!unionInput(x, y)) { //사이클이 생성됨 + cout << i + 1; + return 0; + } + } + cout << 0; + return 0; +} \ No newline at end of file diff --git "a/#17 0524_\354\234\240\353\213\210\354\230\250_\355\214\214\354\235\270\353\223\234/BOJ_20303_sample.cpp" "b/#17 0524_\354\234\240\353\213\210\354\230\250_\355\214\214\354\235\270\353\223\234/BOJ_20303_sample.cpp" new file mode 100644 index 0000000..5c2eb8b --- /dev/null +++ "b/#17 0524_\354\234\240\353\213\210\354\230\250_\355\214\214\354\235\270\353\223\234/BOJ_20303_sample.cpp" @@ -0,0 +1,78 @@ +/* 할로윈의 양아치 : sample */ + +#include +#include + +using namespace std; +typedef pair ci; + +vector parent; + +int knapsack(int n, int k) { + vector cnt; //first: 아이들의 수, second: 사탕 개수 + for (int i = 1; i <= n; i++) { + if (parent[i].first < 0) { + cnt.push_back({-parent[i].first, parent[i].second}); + } + } + vector dp(k, 0); //1부터 k-1까지 + for (int i = 0; i < cnt.size(); i++) { + for (int j = k - 1; j >= cnt[i].first; j--) { + dp[j] = max(dp[j], dp[j - cnt[i].first] + cnt[i].second); + } + } + return dp[k - 1]; +} + +//Find 연산 +int findParent(int node) { + if (parent[node].first < 0) { + return node; + } + return parent[node].first = findParent(parent[node].first); +} + +//Union 연산 +void unionInput(int x, int y) { + int xp = findParent(x); + int yp = findParent(y); + + if (xp == yp) { + return; + } + if (parent[xp].first < parent[yp].first) { + parent[xp].first += parent[yp].first; + parent[yp].first = xp; + parent[xp].second += parent[yp].second; + } else { + parent[yp].first += parent[xp].first; + parent[xp].first = yp; + parent[yp].second += parent[xp].second; + } +} + +/** + * [할로윈의 양아치] + * + * - weighted union find -> 루트 정점에 아이들의 수(집합 원소 수)와 사탕 개수까지 pair 쌍으로 저장하기 + * - dp(냅색)으로 K명 미만의 아이들에게서 뺏을 수 있는 최대 사탕 수 구하기 + */ + +int main() { + int n, m, k, a, b; + + //입력 + cin >> n >> m >> k; + parent.assign(n + 1, {-1, 0}); //first: 아이들의 수, second: 사탕 개수 + for (int i = 1; i <= n; i++) { + cin >> parent[i].second; + } + while (m--) { + cin >> a >> b; + unionInput(a, b); + } + + //연산 & 출력 + cout << knapsack(n, k); + return 0; +} \ No newline at end of file