From f8c2c49df17312e392981f160ee63d66afd768a6 Mon Sep 17 00:00:00 2001 From: joominyoung Date: Tue, 31 May 2022 23:47:56 +0900 Subject: [PATCH] =?UTF-8?q?0524=5F=EC=9C=A0=EB=8B=88=EC=98=A8=ED=8C=8C?= =?UTF-8?q?=EC=9D=B8=EB=93=9C=5F=EA=B3=BC=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### 내용 & 질문 > 과제 제출합니다! 감사합니다 #### <기존 제출> > X #### <추가 제출> > 1043 12100 16114 20040 4195 --- .../1043.txt" | 89 +++++++++++++ .../12100.txt" | 122 ++++++++++++++++++ .../16114.txt" | 42 ++++++ .../20040.txt" | 58 +++++++++ .../4195.txt" | 79 ++++++++++++ 5 files changed, 390 insertions(+) create mode 100644 "0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/1043.txt" create mode 100644 "0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/12100.txt" create mode 100644 "0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/16114.txt" create mode 100644 "0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/20040.txt" create mode 100644 "0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/4195.txt" diff --git "a/0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/1043.txt" "b/0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/1043.txt" new file mode 100644 index 0000000..f7e0ab1 --- /dev/null +++ "b/0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/1043.txt" @@ -0,0 +1,89 @@ +#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); //x의 부모 저장 + int yp = findParent(y); //y의 부모 저장 + + if (xp == yp) { //이미 같은 집합에 있는 경우 + return; //유니온 할 필요 없음. + } + //집합의 크기를 비교 + if (parent[xp] < parent[yp]) { //크기가 작은 경우가 더 높이가 큰 노드. + parent[xp] += parent[yp]; //새로운 루트 xp 추가 + parent[yp] = xp; + } else {//높이가 더 작은 노드 + parent[yp] += parent[xp]; //새로운 루트 yp 추가 + 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); //각각이 자기 자신이 정점인 루트 정점 배열 선언 및 초기화 + //1번부터 n번까지 접근 + + 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/0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/12100.txt" "b/0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/12100.txt" new file mode 100644 index 0000000..4cb702f --- /dev/null +++ "b/0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/12100.txt" @@ -0,0 +1,122 @@ +#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) { //행렬 transpose + matrix board_t(n, vector(n, 0)); //transpose된 행렬 따로 선언 및 초기화 + for (int i = 0; i < n; i++) { //t행렬의 행 + for (int j = 0; j < n; j++) { //t행렬의 열 + 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]) { //0이 아닌 값이 있으면 + 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) { //최대 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]; //0은 빈칸, 이외의 값은 블록을 나타냄 + } + } + + //연산 + backtracking(0, board); + + //출력 + cout << ans; + return 0; +} \ No newline at end of file diff --git "a/0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/16114.txt" "b/0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/16114.txt" new file mode 100644 index 0000000..dc5d1af --- /dev/null +++ "b/0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/16114.txt" @@ -0,0 +1,42 @@ +#include + +using namespace std; + +string solution(int x, int n) { //변수 초기값과 정수 인수로 받음 , +//프로그램의 실행 결과의 타입은 문자열 + if (n > 1 && n % 2 == 1) { //n이 1보다 큰 홀수인 경우 = 2로 나눈 나머지가 1 : ERROR + return "ERROR"; + } + if (n == 1 && x < 0) { //n이 1인데 x가 음수인 경우 while문 조건 항상 참 : INFINITE + return "INFINITE"; + } + if (n == 1 || x <= 0) { // n이 1인데 x가 양수인 경우 or x가 0보다 작거나 같은 경우 : while문 빠져 나감 + return "0"; + } + if (n == 0) { //n이 0인데 x가 양수인 경우는 while문 조건 항상 참이 됨 : INFINITE + return "INFINITE"; + } + return to_string((x - 1) / (n / 2)); //1이상 남을 떄까지만 출력 하므로, 1을 뺀 값에서 몫을 구함 +} + +/** + * [화살표 연산자] + * + * 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; //변수의 초기 값, 정수 N + + //입력 + cin >> x >> n; + + //연산 & 출력 + cout << solution(x, n); //변수 초기값과 정수 인수로 받음 + return 0; +} \ No newline at end of file diff --git "a/0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/20040.txt" "b/0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/20040.txt" new file mode 100644 index 0000000..b3795ed --- /dev/null +++ "b/0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/20040.txt" @@ -0,0 +1,58 @@ +#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); //x의 부모 저장 + int yp = findParent(y); //y의 부모 저장 + + if (xp == yp) { //같은 노드이면 + return false; //false 리턴 + } + if (parent[xp] < parent[yp]) { //크기가 작은 경우가 더 높이가 큰 노드. + parent[xp] += parent[yp]; //새로운 루트 xp 추가 + parent[yp] = xp; + } else {//높이가 더 작은 노드 + parent[yp] += parent[xp]; //새로운 루트 yp 추가 + parent[xp] = yp; + } + return true; //다른 노드일경우 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/0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/4195.txt" "b/0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/4195.txt" new file mode 100644 index 0000000..eb6811b --- /dev/null +++ "b/0524_\354\234\240\353\213\210\354\230\250\355\214\214\354\235\270\353\223\234_\352\263\274\354\240\234/4195.txt" @@ -0,0 +1,79 @@ +#include +#include +#include + +using namespace std; +const int MAX = 2e5; //친구 관계가 모두 다른 사용자로 들어왔을 때의 정점 최댓값 + +vector parent(MAX + 1, -1); // 부모노드 담을 배열 +map people; //사용자의 아이디와 친구의 수 담을 맵 자료구조 + +//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); //x의 부모 저장 + int yp = findParent(y); //y의 부모 저장 + + if (xp == yp) { //부모노드가 같다면 + return; //이미 같은 집합이므로 리턴 + } + //집합의 크기를 비교 + if (parent[xp] < parent[yp]) { //크기가 작은 경우가 더 높이가 큰 노드. + parent[xp] += parent[yp]; //새로운 루트 xp 추가 + parent[yp] = xp; + } else {//높이가 더 작은 노드 + parent[yp] += parent[xp]; //새로운 루트 yp 추가 + parent[xp] = yp; + } +} + +/** + * [친구 네트워크] + * + * 1. weighted union find -> 루트 정점에 친구의 수(집합 원소 수) 저장 + * 2. 친구 네트워크에 몇 명 있는지 구하기 -> 루트 정점의 parent값 접근 + * + * !주의! 정점이 문자열로 들어오므로 map을 활용해 string을 int로 매핑 + */ + +int main() { + ios_base::sync_with_stdio(false); //입출력 속도 향상하기 위함. + cin.tie(NULL); + cout.tie(NULL); + + int t, f; //테스트 케이스의 개수, 친구 관계의 수 + string a, b; //친구 관계인 두 사용자의 아이디 + + //입력 + cin >> t; + while (t--) { //반복되는 테스트 케이스만큼 + int idx = 1; //정점과 매핑할 수 + parent.assign(MAX + 1, -1); //각각 자기 자신이 정점인 배열로 초기화 + + cin >> f; //친구관계의 수 입력 + while (f--) { //각 친구관계 마다 + cin >> a >> b; //두 사용자의 아이디 입력 + if (!people[a]) { // + people[a] = idx++; //친구의 수 증가시킴. + } + if (!people[b]) { + people[b] = idx++; //친구의 수 증가시킴. + } + + //연산 + int x = people[a], y = people[b]; //a와 b 친구관계 저장 + unionInput(x, y); //유니온 연산 + + //출력 + cout << -parent[findParent(x)] << '\n'; + } + } + return 0; +} \ No newline at end of file