'∙ETC > 취준' 카테고리의 다른 글
[ETC] 2019 농협정보시스템 인적성 후기 (6) | 2019.10.12 |
---|---|
[ETC] 2019 동원엔터프라이즈 인적성 후기 (1) | 2019.10.12 |
[ETC] 2019 싸이버로지텍 코딩테스트 후기 (0) | 2019.10.12 |
[ETC] 2019 11번가 인턴 SKCT 및 코딩테스트 후기 (0) | 2019.04.27 |
[ETC] 2019 농협정보시스템 인적성 후기 (6) | 2019.10.12 |
---|---|
[ETC] 2019 동원엔터프라이즈 인적성 후기 (1) | 2019.10.12 |
[ETC] 2019 싸이버로지텍 코딩테스트 후기 (0) | 2019.10.12 |
[ETC] 2019 11번가 인턴 SKCT 및 코딩테스트 후기 (0) | 2019.04.27 |
[ETC] 2019 농협정보시스템 인적성 후기 (6) | 2019.10.12 |
---|---|
[ETC] 2019 동원엔터프라이즈 인적성 후기 (1) | 2019.10.12 |
[ETC] 2019 싸이버로지텍 코딩테스트 후기 (0) | 2019.10.12 |
[ETC] 2019 CJ인적성(CJAT) 후기 (5) | 2019.04.27 |
Stack 자료구조를 할용해 풀 수 있는 문제다.
1. 처음 Stack에 값을 넣는다.
2. Stack이 비어있을 때까지 돌면서 자신보다 큰 탑을 찾는다.
2 -1. 자신보다 큰 값을 찾으면 해당 탑의 idx를 출력
2-2. 자신보다 큰 값이 없다면 0 출력
3. Stack에 자신의 값 추가
2~3 과정을 반복하면 풀 수 있는 문제다.
KOI 통신연구소는 레이저를 이용한 새로운 비밀 통신 시스템 개발을 위한 실험을 하고 있다. 실험을 위하여 일직선 위에 N개의 높이가 서로 다른 탑을 수평 직선의 왼쪽부터 오른쪽 방향으로 차례로 세우고, 각 탑의 꼭대기에 레이저 송신기를 설치하였다. 모든 탑의 레이저 송신기는 레이저 신호를 지표면과 평행하게 수평 직선의 왼쪽 방향으로 발사하고, 탑의 기둥 모두에는 레이저 신호를 수신하는 장치가 설치되어 있다. 하나의 탑에서 발사된 레이저 신호는 가장 먼저 만나는 단 하나의 탑에서만 수신이 가능하다.
예를 들어 높이가 6, 9, 5, 7, 4인 다섯 개의 탑이 수평 직선에 일렬로 서 있고, 모든 탑에서는 주어진 탑 순서의 반대 방향(왼쪽 방향)으로 동시에 레이저 신호를 발사한다고 하자. 그러면, 높이가 4인 다섯 번째 탑에서 발사한 레이저 신호는 높이가 7인 네 번째 탑이 수신을 하고, 높이가 7인 네 번째 탑의 신호는 높이가 9인 두 번째 탑이, 높이가 5인 세 번째 탑의 신호도 높이가 9인 두 번째 탑이 수신을 한다. 높이가 9인 두 번째 탑과 높이가 6인 첫 번째 탑이 보낸 레이저 신호는 어떤 탑에서도 수신을 하지 못한다.
탑들의 개수 N과 탑들의 높이가 주어질 때, 각각의 탑에서 발사한 레이저 신호를 어느 탑에서 수신하는지를 알아내는 프로그램을 작성하라.
첫째 줄에 탑의 수를 나타내는 정수 N이 주어진다. N은 1 이상 500,000 이하이다. 둘째 줄에는 N개의 탑들의 높이가 직선상에 놓인 순서대로 하나의 빈칸을 사이에 두고 주어진다. 탑들의 높이는 1 이상 100,000,000 이하의 정수이다.
첫째 줄에 주어진 탑들의 순서대로 각각의 탑들에서 발사한 레이저 신호를 수신한 탑들의 번호를 하나의 빈칸을 사이에 두고 출력한다. 만약 레이저 신호를 수신하는 탑이 존재하지 않으면 0을 출력한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | import java.io.*; import java.util.*; public class Main { public static StringTokenizer stk; public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); int n = Integer.parseInt(br.readLine()); Stack<Pair> stack = new Stack<>(); stk = new StringTokenizer(br.readLine()); for (int i = 1; i <= n; i++) { int val = Integer.parseInt(stk.nextToken()); if (stack.isEmpty()) { stack.push(new Pair(i, val)); bw.write("0 "); continue; } while (!stack.isEmpty()) { if (stack.peek().val >= val) { //stack.peek에 부딪히면 bw.write(stack.peek().idx + " "); break; } else { stack.pop(); } } if (stack.isEmpty()) bw.write("0 "); stack.push(new Pair(i, val)); } bw.flush(); bw.close(); } public static class Pair { int idx, val; public Pair(int idx, int val) { this.idx = idx; this.val = val; } } } | cs |
[Algorithm] 백준/1026 :: 보물 (0) | 2019.04.30 |
---|---|
[Algorithm] 백준/2504 :: 괄호의 값 (0) | 2019.04.29 |
[Algorithm] 백준/1655 :: 가운데를 말해요 (0) | 2019.04.21 |
[Algorithm] 백준/1946 :: 신입 사원 (0) | 2019.03.24 |
시험 당시에는 17143번 낚시왕 문제보다 복잡해보여서 풀지 않았는데,
다시 풀어보니 역시 풀만한 문제였다.
특별한 알고리즘 기법이 필요없이 단순히 새로운 크기의 맵을 하나 더 만들어서
새로운 맵에 시뮬레이션한 결과를 저장하고 이를 다시 원래맵에 돌려주기만 하면 된다.
미세먼지를 제거하기 위해 구사과는 공기청정기를 설치하려고 한다. 공기청정기의 성능을 테스트하기 위해 구사과는 집을 크기가 R×C인 격자판으로 나타냈고, 1×1 크기의 칸으로 나눴다. 구사과는 뛰어난 코딩 실력을 이용해 각 칸 (r, c)에 있는 미세먼지의 양을 실시간으로 모니터링하는 시스템을 개발했다. (r, c)는 r행 c열을 의미한다.
공기청정기는 항상 왼쪽 열에 설치되어 있고, 크기는 두 행을 차지한다. 공기청정기가 설치되어 있지 않은 칸에는 미세먼지가 있고, (r, c)에 있는 미세먼지의 양은 Ar,c이다.
1초 동안 아래 적힌 일이 순서대로 일어난다.
공기청정기의 바람은 다음과 같은 방향으로 순환한다.
방의 정보가 주어졌을 때, T초가 지난 후 구사과의 방에 남아있는 미세먼지의 양을 구해보자.
첫째 줄에 R, C, T (6 ≤ R, C ≤ 50, 1 ≤ T ≤ 1,000) 가 주어진다.
둘째 줄부터 R개의 줄에 Ar,c (-1 ≤ Ar,c ≤ 1,000)가 주어진다. 공기청정기가 설치된 곳은 Ar,c가 -1이고, 나머지 값은 미세먼지의 양이다. -1은 2번 위아래로 붙어져 있고, 가장 윗 행, 아랫 행과 두 칸이상 떨어져 있다.
첫째 줄에 T초가 지난 후 구사과 방에 남아있는 미세먼지의 양을 출력한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | import java.io.*; import java.util.*; public class Main { public static StringTokenizer stk; public static Cleaner[] cleaner_pos = new Cleaner[2]; //공기청정기 위치 저장 public static int r, c, t; public static int[][] map; public static int[] dx = {1, -1, 0, 0}; public static int[] dy = {0, 0, 1, -1}; public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); stk = new StringTokenizer(br.readLine()); r = Integer.parseInt(stk.nextToken()); c = Integer.parseInt(stk.nextToken()); t = Integer.parseInt(stk.nextToken()); map = new int[r][c]; int idx = 0; for (int i = 0; i < r; i++) { stk = new StringTokenizer(br.readLine()); for (int j = 0; j < c; j++) { map[i][j] = Integer.parseInt(stk.nextToken()); if (map[i][j] == -1) { cleaner_pos[idx++] = new Cleaner(i, j); } } } for (int i = 0; i < t; i++) { spreadStart(new int[r][c]); cleanerStart(new int[r][c]); } getAns(); } public static void spreadStart(int[][] nmap) { for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) { nmap[i][j] += map[i][j]; if (map[i][j] < 5) continue; int spreadCnt = map[i][j] / 5; for (int k = 0; k < 4; k++) { int ny = i + dy[k]; int nx = j + dx[k]; //해당 맵에 퍼트릴 수 있는지 확인 if (ny >= 0 && ny < r && nx >= 0 && nx < c && map[ny][nx] != -1) { nmap[i][j] -= spreadCnt; nmap[ny][nx] += spreadCnt; } } } } spreadCopy(nmap); } public static void cleanerStart(int[][] nmap) { for (int idx = 0; idx < 2; idx++) { Cleaner curr = cleaner_pos[idx]; int ny = curr.r; int nx = curr.c + 1; //오른쪽으로 끝까지 while (nx < c - 1) { nmap[ny][nx + 1] = map[ny][nx]; nx++; } //상하로 끝까지 if (idx == 0) { while (ny > 0) { nmap[ny - 1][nx] = map[ny][nx]; ny--; } } else { while (ny < r - 1) { nmap[ny + 1][nx] = map[ny][nx]; ny++; } } //좌측으로 끝까지 while (nx > 0) { nmap[ny][nx - 1] = map[ny][nx]; nx--; } //공기청정기 위치 전까지 if (idx == 0) { while (ny < curr.r - 1) { nmap[ny + 1][nx] = map[ny][nx]; ny++; } } else { while (ny > curr.r + 1) { nmap[ny - 1][nx] = map[ny][nx]; ny--; } } } cleanerCopy(nmap); } public static void spreadCopy(int[][] nmap) { for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) { map[i][j] = nmap[i][j]; } } } public static void cleanerCopy(int[][] nmap) { for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) { if (i == 0 || i == r - 1 || j == 0 || j == c - 1 || i == cleaner_pos[0].r || i == cleaner_pos[1].r) { map[i][j] = nmap[i][j]; } } } map[cleaner_pos[0].r][cleaner_pos[0].c] = -1; map[cleaner_pos[1].r][cleaner_pos[1].c] = -1; } public static void getAns() { int ans = 0; for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) { if (map[i][j] <= 0) continue; ans += map[i][j]; } } System.out.println(ans); } public static class Cleaner { int r, c; public Cleaner(int r, int c) { this.r = r; this.c = c; } } } | cs |
[Algorithm] 백준/17143 :: 낚시왕 (0) | 2019.04.15 |
---|---|
[Algorithm] 백준/17136 :: 색종이 붙이기 (1) | 2019.04.13 |
[Algorithm] 백준/17135 :: 캐슬 디펜스 (0) | 2019.04.06 |
[Algorithm] 백준/15685 :: 드래곤 커브 (0) | 2019.04.05 |
처음에는 그냥 우선순위 큐를 두개썻는데 메모리 초과가 낫다.
해결하기 위해 최소 힙, 최대 힙으로 변경했다.
핵심 개념은 최대 힙의 peek는 최소 힙의 peek보다 작거나 같아야 한다.
수빈이는 동생에게 "가운데를 말해요" 게임을 가르쳐주고 있다. 수빈이가 정수를 하나씩 외칠때마다 동생은 지금까지 수빈이가 말한 수 중에서 중간값을 말해야 한다. 만약, 그동안 수빈이가 외친 수의 개수가 짝수개라면 중간에 있는 두 수 중에서 작은 수를 말해야 한다.
예를 들어 수빈이가 동생에게 1, 5, 2, 10, -99, 7, 5를 순서대로 외쳤다고 하면, 동생은 1, 1, 2, 2, 2, 2, 5를 차례대로 말해야 한다. 수빈이가 외치는 수가 주어졌을 때, 동생이 말해야 하는 수를 구하는 프로그램을 작성하시오.
첫째 줄에는 수빈이가 외치는 정수의 개수 N이 주어진다. N은 1보다 크거나 같고, 100,000보다 작거나 같은 자연수이다. 그 다음 N줄에 걸쳐서 수빈이가 외치는 정수가 차례대로 주어진다. 정수는 -10,000보다 크거나 같고, 10,000보다 작거나 같다.
한 줄에 하나씩 N줄에 걸쳐 수빈이의 동생이 말해야하는 수를 순서대로 출력한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | import java.io.*; import java.util.*; public class Main { public static StringTokenizer stk; public static StringBuilder sb = new StringBuilder(); public static PriorityQueue<Integer> minHeap; public static PriorityQueue<Integer> maxHeap; public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(br.readLine()); int[] num = new int[n]; minHeap = new PriorityQueue<>(Comparator.naturalOrder()); maxHeap = new PriorityQueue<>(Comparator.reverseOrder()); for (int i = 0; i < n; i++) { num[i] = Integer.parseInt(br.readLine()); if (i == 0) { maxHeap.add(num[i]); sb.append(num[i] + "\n"); continue; } if (i % 2 == 0) { maxHeap.add(num[i]); } else { minHeap.add(num[i]); } if (changeCheck()) { swap(); } sb.append(maxHeap.peek() + "\n"); } System.out.println(sb); } public static boolean changeCheck() { if (minHeap.isEmpty() || maxHeap.isEmpty()) return false; return minHeap.peek() <= maxHeap.peek(); } public static void swap() { int minTomax = minHeap.poll(); int maxTomin = maxHeap.poll(); minHeap.add(maxTomin); maxHeap.add(minTomax); } } | cs |
[Algorithm] 백준/2504 :: 괄호의 값 (0) | 2019.04.29 |
---|---|
[Algorithm] 백준/2493 :: 탑 (0) | 2019.04.27 |
[Algorithm] 백준/1946 :: 신입 사원 (0) | 2019.03.24 |
[Algorithm] 백준/1931 :: 회의실배정 (0) | 2019.03.07 |
2019 상반기 공채 오전반 복원문제중 2번문제였다.
기본 삼성유형으로 알려진 BFS, DFS에서 그냥 구현문제가 나올줄은 몰랏지만
쉬웠다는 평이 많은 상반기 코테에서 1솔로 가능할지 의문이다.
이 문제에서는 주의할 점이 두가지 있다.
1. 물고기들 각각을 움직일 때 바로 움직이지 않고, 한번에 움직여야 한다.
필자는 Fish 배열을 만들어 정보를 저장하고 상어 움직임이 끝낫을 때 한번에 이동했다.
물론, 조건에 따라 해당 좌표에 자신보다 작은 상어가 있다면 Fish 배열에 null로 바꿔주면 된다.
2. 시간 속도를 줄이려면 움직여야 하는 거리 % (Width or Depth * 2 - 2) 계산을 하고 움직이면 된다.(584ms -> 308ms)
아쉽게도 시험장에서 30분을 고민하다 이 공식을 못찾았다.
이 두가지 조건만 만족하면 어렵지 않게 풀수있는 기출문제다.
낚시왕이 상어 낚시를 하는 곳은 크기가 R×C인 격자판으로 나타낼 수 있다. 격자판의 각 칸은 (r, c)로 나타낼 수 있다. r은 행, c는 열이고, (R, C)는 아래 그림에서 가장 오른쪽 아래에 있는 칸이다. 칸에는 상어가 최대 한 마리 들어있을 수 있다. 상어는 크기와 속도를 가지고 있다.
낚시왕은 가장 처음에 1번 열의 한 칸 왼쪽에 있다. 다음은 1초 동안 일어나는 일이며, 아래 적힌 순서대로 일어난다. 낚시왕은 가장 오른쪽 열의 오른쪽 칸에 이동하면 이동을 멈춘다.
상어는 입력으로 주어진 속도로 이동하고, 속도의 단위는 칸/초이다. 상어가 이동하려고 하는 칸이 격자판의 경계인 경우에는 방향을 반대로 바꿔서 속력을 유지한채로 이동한다.
왼쪽 그림의 상태에서 1초가 지나면 오른쪽 상태가 된다. 상어가 보고 있는 방향이 속도의 방향, 왼쪽 아래에 적힌 정수는 속력이다. 오른쪽 위에 상어를 구분하기 위해 문자를 적어 놓았다.
상어가 이동을 마친 후에 한 칸에 상어가 두 마리 이상 있을 수 있다. 이때는 크기가 가장 큰 상어가 나머지 상어를 모두 잡아먹는다.
낚시왕이 상어 낚시를 하는 격자판의 상태가 주어졌을 때, 낚시왕이 잡은 상어 크기의 합을 구해보자.
첫째 줄에 격자판의 크기 R, C와 상어의 수 M이 주어진다. (2 ≤ R, C ≤ 100, 0 ≤ M ≤ R×C)
둘째 줄부터 M개의 줄에 상어의 정보가 주어진다. 상어의 정보는 다섯 정수 r, c, s, d, z (1 ≤ r ≤ R, 1 ≤ c ≤ C, 0 ≤ s ≤ 1000, 1 ≤ d ≤ 4, 1 ≤ z ≤ 10000) 로 이루어져 있다. (r, c)는 상어의 위치, s는 속력, d는 이동 방향, z는 크기이다. d가 1인 경우는 위, 2인 경우는 아래, 3인 경우는 오른쪽, 4인 경우는 왼쪽을 의미한다.
두 상어가 같은 크기를 갖는 경우는 없고, 하나의 칸에 둘 이상의 상어가 있는 경우는 없다.
낚시왕이 잡은 상어 크기의 합을 출력한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | import java.io.*; import java.util.*; public class Main { public static StringTokenizer stk; public static StringBuilder sb = new StringBuilder(); public static int[] dy = {-1, 1, 0, 0}; public static int[] dx = {0, 0, 1, -1}; public static int width, depth, n, ans = 0; public static Fish[] fishInfo = new Fish[10001]; public static int[][] map; public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); stk = new StringTokenizer(br.readLine()); depth = Integer.parseInt(stk.nextToken()); width = Integer.parseInt(stk.nextToken()); n = Integer.parseInt(stk.nextToken()); map = new int[depth + 1][width + 1]; for (int i = 1; i <= n; i++) { stk = new StringTokenizer(br.readLine()); int r = Integer.parseInt(stk.nextToken()); int c = Integer.parseInt(stk.nextToken()); int s = Integer.parseInt(stk.nextToken()); int d = Integer.parseInt(stk.nextToken()); int z = Integer.parseInt(stk.nextToken()); fishInfo[z] = new Fish(z, c, r, d - 1, s); map[r][c] = z; } for (int i = 1; i <= width; i++) { //작살로 물고기 잡음 for (int j = 1; j <= depth; j++) { if (map[j][i] != 0) { fishInfo[map[j][i]] = null; ans += map[j][i]; map[j][i] = 0; break; } } //물고기 이동 for (int j = 1; j <= 10000; j++) { if (fishInfo[j] == null) continue; Fish curr = fishInfo[j]; int nx = curr.x; int ny = curr.y; int move = curr.speed; int d = curr.d; map[ny][nx] = 0; switch (d) { //방향따라 case 다르게 //상하 case 0: case 1: move %= (depth * 2 - 2); while (move > 0) { if (ny == 1) { d = 1; } if (ny == depth) { d = 0; } ny += dy[d]; move--; } fishInfo[curr.idx] = new Fish(curr.idx, nx, ny, d, curr.speed); break; //좌우 case 2: case 3: move %= (width * 2 - 2); while (move > 0) { if (nx == 1) d = 2; if (nx == width) d = 3; nx += dx[d]; move--; } fishInfo[curr.idx] = new Fish(curr.idx, nx, ny, d, curr.speed); break; } } for (int j = 1; j <= 10000; j++) { if (fishInfo[j] == null) continue; Fish curr = fishInfo[j]; if (map[curr.y][curr.x] < curr.idx) { //맵에 저장된 물고기보다 본인이 더 크면 fishInfo[map[curr.y][curr.x]] = null; map[curr.y][curr.x] = curr.idx; } } } System.out.println(ans); } public static class Fish { int idx, x, y, d, speed; public Fish(int idx, int x, int y, int d, int speed) { this.idx = idx; this.x = x; this.y = y; this.d = d; this.speed = speed; } } } | cs |
[Algorithm] 백준/17144 :: 미세먼지 안녕! (0) | 2019.04.25 |
---|---|
[Algorithm] 백준/17136 :: 색종이 붙이기 (1) | 2019.04.13 |
[Algorithm] 백준/17135 :: 캐슬 디펜스 (0) | 2019.04.06 |
[Algorithm] 백준/15685 :: 드래곤 커브 (0) | 2019.04.05 |
삼성 4월 역량테스트에 나왔던 문제다.
Backtracking으로 구현하면 되지만, 최적화를 하지 않으면 시간이 무지오래걸린다.
우선, 구현 순서에 대해 알아보면
이런 방식으로 진행되는 Backtracking 방식이다.
하지만, 단순하게 조건만 따라 구현하면 시간 초과가 날 수밖에 없다.
이를 위해 다음과 같은 방법을 사용한다.
가지치기 때문에 정말 고생이 많았던 문제다.
코드가 깔끔하지는 않지만 누군가에게 도움이 되길 바라며 공유한다.
<그림 1>과 같이 정사각형 모양을 한 다섯 종류의 색종이가 있다. 색종이의 크기는 1×1, 2×2, 3×3, 4×4, 5×5로 총 다섯 종류가 있으며, 각 종류의 색종이는 5개씩 가지고 있다.
<그림 1>
색종이를 크기가 10×10인 종이 위에 붙이려고 한다. 종이는 1×1 크기의 칸으로 나누어져 있으며, 각각의 칸에는 0 또는 1이 적혀 있다. 1이 적힌 칸은 모두 색종이로 덮여져야 한다. 색종이를 붙일 때는 종이의 경계 밖으로 나가서는 안되고, 겹쳐도 안된다. 또, 칸의 경계와 일치하게 붙여야 한다. 0이 적힌 칸에는 색종이가 있으면 안된다.
종이가 주어졌을 때, 1이 적힌 모든 칸을 붙이는데 필요한 색종이의 최소 개수를 구해보자.
총 10개의 줄에 종이의 각 칸에 적힌 수가 주어진다.
모든 1을 덮는데 필요한 색종이의 최소 개수를 출력한다. 1을 모두 덮는 것이 불가능한 경우에는 -1을 출력한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | import java.io.*; import java.util.*; public class Main { public static StringTokenizer stk; public static StringBuilder sb = new StringBuilder(); public static int[] paper = {0, 5, 5, 5, 5, 5}; public static int[][] map = new int[10][10]; public static int ans = Integer.MAX_VALUE, one_cnt = 0; public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); for (int i = 0; i < 10; i++) { stk = new StringTokenizer(br.readLine()); for (int j = 0; j < 10; j++) { map[i][j] = Integer.parseInt(stk.nextToken()); one_cnt += map[i][j]; //1의 개수 세기 } } //r = 해당 row, cnt = 사용한 색종이수, total = 제거한 1의 개수 Backtracking(0, 0, 0); System.out.println(ans == Integer.MAX_VALUE ? -1 : ans); } public static void Backtracking(int r, int cnt, int total) { if (ans <= cnt) return; //현재 값보다 색종이를 많이쓰면 가지치기 if (total == one_cnt) { //1을 다 채운 경우 ans = Math.min(ans, cnt); return; } for (int i = r; i < 10; i++) { //r부터 시작 for (int j = 0; j < 10; j++) { if (map[i][j] == 1) { boolean flag = false; //큰 색종이로 덮을 수 있으면 이후 색종이는 확인해 보지 않아도 된다 for (int k = 5; k >= 1; k--) { if ((i + k) <= 10 && (j + k) <= 10 && paper[k] > 0) { if (!flag) { flag = check(i, j, k); //k*k 색종이를 덮을 수 있으면 check = true } if (flag) { setVisited(i, j, k); paper[k]--; Backtracking(i, cnt + 1, total + k * k); paper[k]++; setVisited(i, j, k); } } } if (!flag) return; //색종이를 못덮는 경우 } if (map[i][j] == 1) return; //덮고나서도 해당좌표를 못지우는경우 } } } //size만큼의 색종이를 사용할 수 있는지 확인 public static boolean check(int r, int c, int size) { for (int i = r; i < r + size; i++) { for (int j = c; j < c + size; j++) { if (map[i][j] == 0) return false; } } return true; } //방문한 점을 XOR 연산 public static void setVisited(int r, int c, int size) { for (int i = r; i < r + size; i++) { for (int j = c; j < c + size; j++) { map[i][j] = map[i][j] ^ 1; } } } } | cs |
[Algorithm] 백준/17144 :: 미세먼지 안녕! (0) | 2019.04.25 |
---|---|
[Algorithm] 백준/17143 :: 낚시왕 (0) | 2019.04.15 |
[Algorithm] 백준/17135 :: 캐슬 디펜스 (0) | 2019.04.06 |
[Algorithm] 백준/15685 :: 드래곤 커브 (0) | 2019.04.05 |
프로세스가 병행 또는 병렬로 실행될 때 여러 프로세스가 공유하는 데이터의 무결성이 유지되어야 한다.
병행 프로세스는 다중 처리 시스템이나 분산 처리 시스템에서 중요 개념으로 사용
한 프로세스가 자신의 임계구역에서 수행하는 동안에는 다른 프로세스들은 그들의 임계구역에 들어갈 수 없다
임계구역 안에서는 공유 변수를 변경, 테이블 갱신, 파일 쓰기 등의 작업을 수행한다.
임계구역에는 하나의 프로세스만 접근할 수 있으며, 해당 프로세스가 자원을 반납해야 다른 프로세스가 자원 및 데이터를 사용할 수 있다
특정 프로세스가 공유 자원을 사용하고 있을 경우 다른 프로세스가 해당 공유 자원을 사용하지 못하게 제어하는 기법
두 개의 프로세스 기준 : 피터슨 알고리즘(두 프로세스가 두 개의 데이터 항목을 공유하여 자원을 사용하는 방법)
여러 개의 프로세스 기준 : Lamport의 빵집 알고리즘(각 프로세스에 번호를 부여하여 자원을 사용하도록 하는 방볍)
자신의 임계구역에서 실행되는 프로세스가 없고 자신의 임계구역으로 진입하려는 프로세스가 있다면,
잔류 구역에서 실행 중이지 않은 프로세스들만 임계영역에 진입 대상이 되고, 이 선택은 무한정 연기되지 않음!
프로세스가 자기의 임계구역에 진입하려는 요청을 한 후로부터 요청이 허용될 때까지 다른 프로세스들이 임계영역에 그들 자신의 임계구역에 진입을 허용하는 횟수의 한계가 필요
>> Mutex가 지켜주는 덕에 화장실을 한명만 사용할 수 있다.
즉, Mutex는 임계구역을 보호하고 프로세스간 경쟁을 방지하기 위해 사용
boolean available 변수를 사용 => 락의 가용 여부 표시
1 2 3 4 5 6 | do { //Lock 획득 임계구역 //Lock 반환 나머지 구역 } while(true); | cs |
Mutex와 유사하게 동작하지만 프로세스들이 자신들의 행동을 더 정교하게 동기화 할 수 있는 방법 제공
각 프로세스에 제어신호를 전달하여 순차적으로 진행하기 위한 동기화 구현
세마포 S = 정수 변수, wait(s)와 signal(s)로만 접근이 가능하다. S = 0인 경우 모든 자원이 사용 중을 의미
1 2 3 4 5 6 | //wait(S) //임계구역에 진입하기 전에 확인 if (S <= 0) //누군가 사용하고 있다면 S가 양수가 될 때까지 현재 프로세스를 list에서 기다림 else //임계 구역에 진입이 가능하다면 S = S - 1; | cs |
1 2 3 4 5 6 | //Signal(S) //임계구역을 떠날 때 실행 if (자원 반환전에 list에서 기다리는 프로세스가 있다면) 그 중 한개 프로세스를 임계 구역 진입 else //list에서 기다리는 프로세스가 없다면 S = S + 1; | cs |
=> 진행 보장
생산자가 데이터를 생산하여 입력된 경우에만 접근하도록 구성하는 방식
생산자는 꽉찬 버퍼를 생산하고 소비자는 비어있는 버퍼를 생산한다.
두 Reader가 동시에 공유 데이터를 접근하는 것은 허용하나, 동시에 Writer를 허용하지 않는 방식
Writer보다 Reader 요청이 많은 경우 병행성을 높일 수 있다.
5명의 철학자들은 생각하고 먹는 일을 수행(철학자 : 프로세스, 젓가락 : 자원)
5명의 철학자가 동시에 식사를 하게 되면 모두 왼쪽 포크만을 가지게 되고 오른쪽 포크를 대기하는 교착 상태(Deadlock)이 발생한다.
이를 방자힉 위한 방법은 대표적으로 3가지이다.
[정보처리기사]기억장치 관리 (0) | 2020.06.30 |
---|---|
[정보처리기사]프로세스 동기화 (0) | 2020.06.30 |
[정보처리기사]운영체제와 CPU 스케쥴링 (0) | 2020.06.30 |
[OS] 운영체제와 CPU 스케쥴링 (0) | 2019.04.09 |