diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2a09375
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.idea/*
+
+*.iml
\ No newline at end of file
diff --git a/contents/divide_and_conquer.md b/contents/divide_and_conquer.md
new file mode 100644
index 0000000..6c2d0eb
--- /dev/null
+++ b/contents/divide_and_conquer.md
@@ -0,0 +1,23 @@
+# Divide and Conquer 알고리즘
+
+- '분할정복' 기법 이라고도 부릅니다.
+- 문제(problem)를 잘게 쪼개면서(sub-problem) 풀어나가고 다시 병합하며 해를 찾는 알고리즘 입니다.
+- 상위 문제를 구하기 위해 아래로 내려가며 답을 찾는 하향식 접근법
+- [divide and conquer](https://www.youtube.com/watch?v=2Rr2tW9zvRg)
+
+
+### 알고리즘 설계 조언
+1. Divide: 분할이 가능한 문제라면 분할 기준을 선택하여 문제를 2개 이상으로 나눈다.
+2. Conquer: 분할이 불가능한 경우 문제를 푼다.
+3. Combine: 정복한 문제를 병합하여 해를 찾는다. 제대로 나누면 병합하기도 쉽다.
+
+
+### 알고리즘 효율성
+- 분할정복 알고리즘은 Recursion calls(재귀호출)가 사용되는 경우가 많다. 재귀호출에서 알고리즘 효율이 떨어질 수 있다. => 분할 기준에 따라 효율이 달라질 수 있다.
+
+
+### 분할정복 관련 자료
+
+- [백준 Z](https://www.google.com/search?q=%EB%B0%B1%EC%A4%80+z+%EB%AC%B8%EC%A0%9C&oq=%EB%B0%B1%EC%A4%80+z+%EB%AC%B8%EC%A0%9C&aqs=chrome..69i57j0l9.3894j0j7&sourceid=chrome&ie=UTF-8)
+- [별 찍기 풀이](https://st-lab.tistory.com/95)
+- https://gamedevlog.tistory.com/58
diff --git a/contents/greedy.md b/contents/greedy.md
index a557839..096b9e6 100644
--- a/contents/greedy.md
+++ b/contents/greedy.md
@@ -4,35 +4,37 @@
- 문제를 작은 단위로 쪼개 반복적으로 진행하며 접근하는 방식이다.
- 탐욕법은 각 단계마다 현재에 충실한 선택을 한다.
- 미래의 선택, 최종 결과는 고려하지 않는다.
-- 반드시 최적의 해를 보장하는건 아니다.
-- 문제를 작은 단위로 쪼개 풀다보면 같은 문제를 반복해 푸는 경우가 있는데 이 때 그 문제들을 매번 재계산 하지 않고 값을 저장해두었다가 재사용 하는 동적프로그래밍(DP) 기법을 이용 할 수 있다.
- - [DP 요약설명](https://github.com/TheCopiens/algorithm-study/blob/master/contents/DP.md)
-
-### 탐욕법 문제 풀이 순서
-- 회의실 예약을 예시로 설명합니다. 하나의 회의실을 겹치치 않고 최다로 사용할때 몇개의 회의를 진행 할 수 있을까요?
-1. 문제의 답을 내는 과정을 여러 부분으로 나눈다.
-2. 방식 결정. 어떤 우선순위로 탐욕적 선택을 할지 결정한다.
- - 회의 시간이 가장 짧은 회의부터 선택, 가장 먼저 끝나는 회의부터 선택
-3. 탐욕적 선택 속성, 최적 부분 구조 를 만족하는지 따져본다.
- - 탐욕적 선택 속성: 답의 모든 부분을 고려하지 않고 탐욕적 선택만 하더라도 최적의 해를 구할 수 있는 속성
- - 모든 단계의 최적해에 '종료시간이 빠른 회의'라는 탐욕적 기준으로 선택한 회의가 존재할까?
- - 최적 부분 구조 : 주어진 문제가 **부분 문제의 최적해**로 **전체 문제의 최적해**를 만들 수 있는 구조인지 나타내는 속성
- - 가장 빨리 끝나는 회의를 선택하면 가장 많은 회의를 선택 할 수 있다.
-
-
-1. 해 선택
- - 현재 단계에 가장 최적의 해를 구해서 부분해 집합에 포함시킨다.
-2. 조건으로 적절성 검사
- - 포함시킨 부분해 집합이 문제의 조건을 만족하는지 검사한다.
- - 만족하지 않을 경우, 한 단계 전으로 돌아가 다른 해를 구해 부분해 집합에 포함한다
-3. 해 검사
- - 포함시킨 부분해 집합이 문제의 해가 되는지 검사한다.
- - 아직 문제의 해가 완성되지 않았다면 1번부터 다시 시작한다.
+- 반드시 최적의 해를 보장하는건 아니므로 '근사치 추정'을 위해 사용한다.
-### 탐욕법을 활용한 문제
-- 동전을 최소 개수로 거슬러주기
-- [체육복](https://github.com/TheCopiens/algorithm-study/blob/ohhako/source/ohhako/200202_greedy.md)
-- [큰수만들기](https://programmers.co.kr/learn/courses/30/lessons/42883)
+### 탐욕법을 적용한 문제 풀이
+- 회의실 예약을 예시로 설명. 회의 시작 시간/끝나는 시간을 갖는 회의 목록이 존재한다. 회의실 하나를 겹치치 않게 최다로 사용할때 몇개의 회의를 진행 할 수 있을까?
+
+- 탐욕적 선택 속성: 앞의 선택이 이후 선택에 영향을 주지 않는다. 답의 모든 부분을 고려하지 않고 탐욕적 선택만 하더라도 최적의 해를 구할 수 있는 속성
+- 최적 부분 구조: 작은 부분 문제에서 구한 최적의 답으로 합쳐진 큰 문제의 최적의 답을 구할 수 있어야 한다.
+
+1. 문제의 답을 내는 과정을 여러 부분으로 나누자
+ - 해: 겹치지 않고 선택한 회의 목록
+ - 최적해: 겹치지 않고 최다로 선택한 회의 목록
+2. 어떤 우선순위로 탐욕적 선택을 할지 선택 속성 결정
+ - 회의 시간이 가장 짧은 회의부터 선택/ 가장 먼저 끝나는 회의부터 선택
+3. 선택 속성이 최적 부분 구조를 만족하는지 따져본다.
+ - 가장 빨리 끝나는 회의를 선택하면 가장 많은 회의를 선택 할 수 있다.
+
+### 알고리즘 개선 방향
+
+문제를 작은 단위로 쪼개 풀다보면 같은 문제를 반복해 푸는 경우가 있는데 이 때 그 문제들을 매번 재계산 하지 않고 값을 저장해두었다가 재사용 하는 동적프로그래밍(DP) 기법을 이용 할 수 있다.
+- [DP 요약설명](https://github.com/TheCopiens/algorithm-study/blob/master/contents/DP.md)
+
+### 탐욕법을 활용한 문제
+* 동전을 최소 개수로 거슬러주기
+* [체육복](https://github.com/TheCopiens/algorithm-study/blob/ohhako/source/ohhako/200202_greedy.md)
+* [큰수만들기](https://programmers.co.kr/learn/courses/30/lessons/42883)
+* [RGB거리](https://github.com/TheCopiens/algorithm-study/blob/master/source/ohhako/boj/1149_dp.md)
+* [정수 삼각형](https://github.com/TheCopiens/algorithm-study/blob/master/source/ohhako/boj/1932_DP.md)
+* [동물원](https://www.acmicpc.net/problem/1309)
+* [기타리스트](https://www.acmicpc.net/problem/1495)
+* [LCS](https://www.acmicpc.net/problem/9251)
+* [동전2](https://www.acmicpc.net/problem/2294)
diff --git "a/contents/\352\270\260\353\263\270\354\240\225\353\240\254.md" "b/contents/\352\270\260\353\263\270\354\240\225\353\240\254.md"
new file mode 100644
index 0000000..1c0cd7f
--- /dev/null
+++ "b/contents/\352\270\260\353\263\270\354\240\225\353\240\254.md"
@@ -0,0 +1,24 @@
+# 기본정렬 알고리즘
+
+## 1. 선택정렬
+구하고자 하는 요소(min or max)를 찾아 swap하는 방식에서 착안하여 정렬에 '선택'이라는 이름이 붙었다.
+- 크기가 n인 일차원 배열에서 첫번쨰 인덱스를 i로 뽑는다.
+- i의 이후(i+1) 요소중 가장 작은 수(minIndex)를 선택해 i와 자리를 바꾼다. (swap)
+- i 다음의 인덱스에서 위 순서를 반복한다.
+- 복잡도 항상 O(n^2)
+
+## 2. 버블정렬
+가장 가까운 인덱스끼리 비교하여 swap하는 과정이 거품이 이는 현상같아 '버블'이라는 이름이 붙었다.
+- 크기가 n인 일차원 배열
+- 인덱스 0부터 n-1까지 순회하며 i와 i+1 요소를 비교한다.
+- 배열을 한번 돌고나면 마지막 요소에는 가장 큰 수가 있다.
+- 마지막 인덱스를 하나씩 줄여가며 위 순서를 반복한다.
+- 복잡도 항상 O(n^2)
+
+## 3. 삽입정렬
+key를 주체로 삽입하는 알고리즘이다. 어떤 값 뒤에 key를 삽입할 것인가? 가 중요하다.
+- 크기가 n인 일차원 배열
+- key는 인덱스 1번부터 시작한다.
+- 배열을 인덱스 0부터 방문하며 key보다 크면 우측으로 모두 밀고 작으면 그 요소의 바로 뒤에 삽입한다.
+- 어느정도 정렬이 되어있는 경우에는 O(n)지만 최악의 평균적으로 복잡도 O(n^2)를 갖는다.
+- 밀어야 하는 요소가 많은 경우 i/o가 많이 일어나는 단점이 있다.
\ No newline at end of file
diff --git "a/contents/\354\235\264\353\266\204\355\203\220\354\203\211.md" "b/contents/\354\235\264\353\266\204\355\203\220\354\203\211.md"
new file mode 100644
index 0000000..52ead54
--- /dev/null
+++ "b/contents/\354\235\264\353\266\204\355\203\220\354\203\211.md"
@@ -0,0 +1,8 @@
+# 이분탐색
+
+- 사용 조건: 정렬된 배열에서 데이터를 찾아야 할 떄.
+- 완전탐색에서 매 반복마다 탐색 범위를 반으로 줄여가며 찾아가는 탐색 방법
+- 예를들어 `1 2 3 4 5 6 7 8 9 10`에서 8을 찾고 싶을때 정가운데 값 5를 찾은 후 왼쪽은 쳐다보지 않고 5의 오른쪽을 탐색 범위로 한다.
+
+문제 목록
+https://www.acmicpc.net/problem/2110
diff --git "a/contents/\354\240\225\353\240\254.md" "b/contents/\354\240\225\353\240\254.md"
new file mode 100644
index 0000000..6c46085
--- /dev/null
+++ "b/contents/\354\240\225\353\240\254.md"
@@ -0,0 +1,24 @@
+# 정렬 알고리즘
+
+## 1. 선택정렬
+구하고자 하는 요소(min or max)를 찾아 swap하는 방식에서 착안하여 정렬에 '선택'이라는 이름이 붙었다.
+- 크기가 n인 일차원 배열에서 첫번쨰 인덱스를 i로 뽑는다.
+- i의 이후(i+1) 요소중 가장 작은 수(minIndex)를 선택해 i와 자리를 바꾼다. (swap)
+- i 다음의 인덱스에서 위 순서를 반복한다.
+- 복잡도 O(n^2)
+
+## 2. 버블정렬
+가장 가까운 인덱스끼리 비교하여 swap하는 과정이 거품이 이는 현상같아 '버블'이라는 이름이 붙었다.
+- 크기가 n인 일차원 배열
+- 인덱스 0부터 n-1까지 순회하며 i와 i+1 요소를 비교한다.
+- 배열을 한번 돌고나면 마지막 요소에는 가장 큰 수가 있다.
+- 마지막 인덱스를 하나씩 줄여가며 위 순서를 반복한다.
+- 복잡도 O(n^2)
+
+## 3. 삽입정렬
+key를 주체로 삽입하는 알고리즘이다. 어떤 값 뒤에 key를 삽입할 것인가? 가 중요하다.
+- 크기가 n인 일차원 배열
+- key는 인덱스 1번부터 시작한다.
+- 배열을 인덱스 0부터 방문하며 key보다 크면 우측으로 모두 밀고 작으면 그 요소의 바로 뒤에 삽입한다.
+- 어느정도 정렬이 되어있는 경우에는 O(n^2)지만 최악의 평균적으로 복잡도 O(n^2)를 갖는다.
+- 밀어야 하는 요소가 많은 경우 i/o가 많이 일어나는 단점이 있다.
\ No newline at end of file
diff --git "a/docs/\354\204\234\353\241\234 \353\213\244\353\245\270 \354\226\270\354\226\264\353\241\234 \354\225\214\352\263\240\353\246\254\354\246\230 \355\225\250\352\273\230 \352\263\265\353\266\200\355\225\230\352\270\260.md" "b/docs/\354\204\234\353\241\234 \353\213\244\353\245\270 \354\226\270\354\226\264\353\241\234 \354\225\214\352\263\240\353\246\254\354\246\230 \355\225\250\352\273\230 \352\263\265\353\266\200\355\225\230\352\270\260.md"
new file mode 100644
index 0000000..446986d
--- /dev/null
+++ "b/docs/\354\204\234\353\241\234 \353\213\244\353\245\270 \354\226\270\354\226\264\353\241\234 \354\225\214\352\263\240\353\246\254\354\246\230 \355\225\250\352\273\230 \352\263\265\353\266\200\355\225\230\352\270\260.md"
@@ -0,0 +1,34 @@
+
+
+### 서로 다른 언어로 알고리즘 함께 공부하기
+
+- 기존에 사용하던 언어 => Java
+
+- 새로 추가된 언어 => JavaScript
+
+- 제안하는 방법
+ - 코드리뷰 시작 전 알고리즘 이론 정리/분석 설명하기
+ - 팀원들과 이 알고리즘에 대해 얘기하는 시간 갖기
+ - JavaScript로 문제를 푸는 것은 옵션!
+
+
+
+#### 어떤 알고리즘을 선택할 것인가?
+
+기존 알고리즘 문제는 그날 문제 리뷰가 끝나고 다음 주에 어떤 문제를 풀지 얘기를 나누면서 선택한다.
+
+- 오늘의 알고리즘! (요즘 각광받고 있는 알고리즘이나 마이너한 알고리즘)
+
+- 기본적인 알고리즘 (BFS,DFS,DP...)
+
+- 팀원들이 푸는 문제와 관련있는 알고리즘
+
+
+
+#### 무엇을 설명할 것인가?
+
+- 동작 방식
+- 복잡도
+- 장/단점
+- 비슷한 알고리즘 유형
+- 대표적인 문제 소개 (풀이는 개인적으로 작성해 업로드)
diff --git a/source/.DS_Store b/source/.DS_Store
new file mode 100644
index 0000000..4fd3577
Binary files /dev/null and b/source/.DS_Store differ
diff --git a/source/diane/[baekjoon]1005.md b/source/diane/[baekjoon]1005.md
new file mode 100644
index 0000000..17db1a3
--- /dev/null
+++ b/source/diane/[baekjoon]1005.md
@@ -0,0 +1,135 @@
+# Baekjoon ACM Craft 문제
+
+- ACM Craft
+ - https://www.acmicpc.net/problem/1005
+
+### 문제 이해하기
+ACM Craft는 건물을 짓는 게임으로, 특정 건물을 지으면 승리할 수 있다.
+건물은 짓는데 걸리는 건설 시간이 있고, 어떤 건물은 다른 특정 건물이 지어진 후에만 건설할 수 있다.
+승리를 위한 건물을 가장 빨리 지을 때까지 걸리는 최소 시간을 알아내자.
+
+#### 입력
+- int T : 테스트케이스 개수
+ - 이 아래 입력은 테스트케이스 개수만큼 반복됨
+- int N, K : 건물의 개수 N, 건설 순서 규칙의 개수 K
+- int D1, D2, ... , DN : 각 건물의 건설에 걸리는 시간
+- int X, Y (*K) : 건설 순서 규칙으로, X 건물이 지어진 후에 Y 건물을 지을 수 있다는 뜻
+ - 건설 순서 규칙이 K번 반복하여 주어짐
+- int W : 승리하기 위해 지어야할 목표 건물
+
+#### 출력
+- int : 목표 건물을 건설 완료하기까지 드는 최소 시간
+
+### 문제 접근 방법
+현재 지을 수 있는 건물들을 찾아 지금 지을 수 있는 건물 목록에 추가한다.
+건물은 이 목록에 추가된 순간부터 즉시 건설되기 시작한다고 가정한다.
+이 목록에서 건설 시간이 가장 짧은 건물을 찾아, 이 건물을 목록에서 제거하고 그 건물이 다 지어진 후의 시간으로 이동한다.
+지금 지을 수 있는 건물 목록의 건물들은 그 건설 시간만큼 이미 지어졌으므로, 이 건물들을 건설하는데 걸리는 시간에서 그만큼 빼준다.
+이 시점에서 지금 지을 수 있는 건물 목록을 업데이트하고, 위 과정을 반복한다.
+그러다가 목표 건물이 지금 지을 수 있는 건물 목록에 추가되는 순간, 그 건물을 건설 시간에 관계 없이 즉시 건설하고 총 시간을 반환한다.
+
+### 구현 배경 지식
+- Topological Sorting
+
+### 문제를 해결한 코드
+~~~java
+import java.util.ArrayList;
+import java.util.Scanner;
+
+public class Main {
+
+ // i번 건물이 지어진 후 지을 수 있는 건물 번호들
+ static ArrayList> nextBuilding;
+ // i번 건물이 지어지기 전에 먼저 지어져야 할 건물들 수
+ static int[] numOfSource;
+ // i번 건물이 지어지는 데에 걸리는 시간
+ static int[] runningTime;
+
+ static int buildings;
+ static int rules;
+ static int target;
+
+ public static void main(String args[]) {
+ Scanner sc = new Scanner(System.in);
+ int testCase = sc.nextInt();
+
+ for (int t=0; t startBuilding = new ArrayList<>();
+ while (true) {
+ // 앞에 해야하는 것이 없는 것들 모으기
+ // = 지금 지을 수 있는 건물
+ for (int i=0; i runningTime[building]) {
+ minTime = runningTime[building];
+ minBuilding = building;
+ }
+ }
+ time += minTime;
+ startBuilding.remove((Integer) minBuilding);
+ for (int b : nextBuilding.get(minBuilding)) {
+ numOfSource[b]--;
+ }
+ for (int b : startBuilding) {
+ runningTime[b]-=minTime;
+ }
+ }
+
+ return time;
+ }
+
+ private static void getInput(Scanner sc) {
+ buildings = sc.nextInt();
+ rules = sc.nextInt();
+
+ nextBuilding = new ArrayList<>();
+ numOfSource = new int[buildings];
+ runningTime = new int[buildings];
+ for (int i=0; i());
+ numOfSource[i] = 0;
+ runningTime[i] = sc.nextInt();
+ }
+
+ for (int i=0; i visited;
+ private static double[] Direction;
+ private static int[] Path;
+
+ public static void main(String args[]) throws Exception {
+ Scanner sc = new Scanner(System.in);
+ Number = sc.nextInt();
+ Path = new int[Number];
+ Direction = new double[4];
+ for (int i=0; i<4; i++) {
+ int temp = sc.nextInt();
+ Direction[i] = (double) temp/100;
+ }
+
+ position = new Position();
+ visited = new HashSet<>();
+ visited.add(position);
+ double simple = backtracking(0);
+
+ System.out.println(simple);
+ }
+
+ private static double backtracking(int depth) throws Exception {
+ if (depth == Number) {
+ return calculate();
+ }
+
+ double result = 0;
+ for (int i=0; i<4; i++) {
+ position.move(i);
+ Path[depth] = i;
+ if (isSimple()) {
+ visited.add(position);
+ result += backtracking(depth+1);
+ visited.remove(position);
+ }
+ position.back(i);
+ }
+ return result;
+ }
+
+ private static boolean isSimple() {
+ return !visited.contains(position);
+ }
+
+ private static double calculate() {
+ double result = 1;
+ for (int d : Path) {
+ result = result*Direction[d];
+ }
+ return result;
+ }
+}
+
+class Position extends Object {
+ public int x;
+ public int y;
+
+ Position() {
+ x=0; y=0;
+ }
+
+ Position(int x, int y) {
+ this.x = x; this.y = y;
+ }
+
+ public void move(int direction) throws Exception {
+ if (direction == 0) {
+ x++;
+ } else if (direction == 1) {
+ x--;
+ } else if (direction == 2) {
+ y--;
+ } else if (direction == 3) {
+ y++;
+ } else {
+ throw new Exception("Invalid direction " + direction);
+ }
+ }
+
+ public void back(int direction) throws Exception {
+ if (direction == 0) {
+ x--;
+ } else if (direction == 1) {
+ x++;
+ } else if (direction == 2) {
+ y++;
+ } else if (direction == 3) {
+ y--;
+ } else {
+ throw new Exception("Invalid direction " + direction);
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass()!=o.getClass()) return false;
+ Position p = (Position) o;
+ return (x==p.x)&&(y==p.y);
+ }
+
+ @Override
+ public int hashCode() {
+ return x*100+y;
+ }
+}
+~~~
\ No newline at end of file
diff --git a/source/diane/[baekjoon]14888.md b/source/diane/[baekjoon]14888.md
new file mode 100644
index 0000000..29e746c
--- /dev/null
+++ b/source/diane/[baekjoon]14888.md
@@ -0,0 +1,101 @@
+# Baekjoon 연산자 끼워넣기
+
+- 연산자 끼워넣기
+ - hhttps://www.acmicpc.net/problem/14888
+
+### 문제 이해하기
+N개의 수로 이루어진 수열이 주어지고, 이 N개의 수 사이에 끼워넣을 (N-1)개의 연산자가 주어진다.
+연산자는 덧셈(+), 뺄셈(-), 곱셈(x), 나눗셈(/)으로만 이루어져 있다.
+수열의 순서를 바꾸지 않으면서, 수 사이에 이 연산자를 끼워넣어 여러 개의 수식을 만들 수 있다.
+이렇게 만들 수 있는 수식의 계산 결과가 최대인 것과 최소인 것을 구하여라.
+(단, 수식의 결과값이나 중간 과정값은 항상 -10억보다 크거나 같고, 10억보다 작거나 같다.)
+
+#### 입력
+- int N : 수열의 길이 (수의 개수, 2<=N<=11)
+- int A1, A2, ... , AN : 수열의 숫자 (1<=A<=100)
+- int op1, op2, op3, op4 : 사용할 수 있는 덧셈, 뺄셈, 곱셈, 나눗셈의 개수
+
+#### 출력
+- int : 최대인 수식의 결과 값
+- int : 최소인 수식의 결과 값
+
+### 문제 접근 방법
+모든 경우를 dfs로 탐색하면서, 만들어진 수식의 값이 지금까지의 결과 중 최대이거나 최소인 경우 그 값을 저장한다.
+
+
+### 구현 배경 지식
+- Backtracking
+- Depth-First Searching
+
+### 문제를 해결한 코드
+~~~java
+import java.util.Scanner;
+
+public class Main {
+
+ private static int[] numbers;
+ private static int[] operations;
+ private static int MIN;
+ private static int MAX;
+
+ public static void main(String args[]) {
+ Scanner sc = new Scanner(System.in);
+ int size = sc.nextInt();
+
+ numbers = new int[size];
+ for (int i=0; i MAX) {
+ MAX = number;
+ }
+ if (number < MIN) {
+ MIN = number;
+ }
+ return;
+ }
+
+ for (int op = 0; op<4; op++) {
+ if (operations[op] > 0) {
+ operations[op]--;
+ int newNumber = calculate(op, numbers[idx], number);
+ putOperation(idx+1, newNumber);
+ operations[op]++;
+ }
+ }
+ }
+
+ private static int calculate(int op, int num, int number) throws Exception {
+ if (op == 0) {
+ return number+num;
+ } else if (op == 1) {
+ return number-num;
+ } else if (op == 2) {
+ return number*num;
+ } else if (op == 3) {
+ return number/num;
+ }
+ throw new Exception("Invaild operation.");
+ }
+}
+~~~
\ No newline at end of file
diff --git a/source/diane/[baekjoon]15684.md b/source/diane/[baekjoon]15684.md
new file mode 100644
index 0000000..05bdc57
--- /dev/null
+++ b/source/diane/[baekjoon]15684.md
@@ -0,0 +1,132 @@
+# Baekjoon 사다리 조작 문제
+
+- 사다리 조작
+ - https://www.acmicpc.net/problem/15684
+
+### 문제 이해하기
+사다리 게임이 있다. 이 사다리 게임은 N개의 세로선과 그 세로선들 사이를 잇는 M개의 가로선으로 이루어져 있다.
+이 사다리 게임에서는 세로선에 총 H개의 가로선을 놓을 수 있는데, 먼저 그려진 가로선도 그 위치에 맞추어 그려져 있다.
+사다리 게임에서 가로선은 인접한 두 세로선을 연결하고, 두 가로선이 연속하거나 접하는 일은 없다.
+주어진 사다리 게임에 가로선을 추가하여 i번 세로선의 결과가 i가 나오도록 만들고 싶다.
+최대 3개의 가로선을 추가하여 조건에 맞는 사다리 게임을 만들 때, 최소 몇 개의 가로선을 추가해야 하는지 구하여라.
+
+#### 입력
+- int N M H : 사다리 게임의 세로선, 가로선 갯수와 세로선에 가로선을 놓을 수 있는 위치의 갯수
+- int a b (x M) : 사다리 게임의 M개의 가로선 위치
+ - b번째 세로선과 (b+1)번째 세로선을 잇는, 세로로 a번 위치에 가로선이 존재
+
+#### 출력
+- int K : 조건을 만족하기 위해 추가해야 하는 가로선 갯수의 최솟값
+ - 정답이 3보다 큰 경우, 또는 불가능한 경우에는 -1을 반환
+
+### 문제 접근 방법
+주어진 사다리 게임에 비어있는 모든 가로선 자리에 가로선을 최대 3개까지 그리면서 조건에 맞는지를 확인할 것이다.
+이에 따라 아래와 같은 상태 공간 트리를 그릴 수 있다.
+
+(가로선 0개) 추가된가로선없음
+ / \
+(가로선 1개) 1번자리가로선 2번자리가로선 ...
+ / \
+(가로선 2개) 2번자리가로선 3번자리가로선 ...
+ / \
+(가로선 3개) 3번자리가로선 4번자리가로선 ...
+
+이 상태 공간 트리를 dfs로 탐색하면서, 각 노드에서 문제의 요구 조건을 충족하는지 확인할 것이다.
+각 노드를 탐색할 때 그 노드가 문제의 기준을 만족하지 않는다면, 그 노드의 자식 노드는 탐색하지 않고, 그 노드의 부모 노드로 돌아가 다른 노드를 탐색할 것이다.
+이 때 사용되는 기준 함수(bounding function)은 다음과 같다. 해당 노드의 상태에서 추가될 가로선이 (1) 이미 존재하지 않고 (2) 왼쪽이나 오른쪽의 가로선과 만나서는 안 된다.
+
+가능성 있는 모든 상태를 탐색하면서, 그 중 조건을 만족하는 상태에서 그 depth를 반환한다.
+추가할 가로선이 어떤 가로선인지를 알고 싶은 것이 아니라, 몇 개의 가로선이 추가되어야 하는지를 알기 위해 그 깊이를 반환하고, 그 깊이 중 최소값을 반환한다.
+만약 깊이가 3을 탐색했는데 조건을 만족하지 않는다면, 그 이상은 탐색하지 않고 -1을 반환한다.
+
+### 구현 배경 지식
+- backtracking
+- dfs
+
+### 문제를 해결한 코드
+~~~java
+import java.util.Scanner;
+
+public class Main {
+ private static int N, M, H;
+ private static boolean[][] ladder;
+ private static int Limit = 3;
+
+ public static void main(String args[]) {
+ Scanner sc = new Scanner(System.in);
+ N = sc.nextInt();
+ M = sc.nextInt();
+ H = sc.nextInt();
+ ladder = new boolean[N][H];
+
+ for (int i=0; i iter) Limit = iter;
+ return iter;
+ }
+
+ if (iter == Limit) {
+ return -1;
+ }
+
+ int result = -1;
+ for (int i=idx; i temp)) result = temp;
+ if (result == iter+1) return result;
+ }
+ }
+ }
+ return result;
+ }
+
+ private static boolean makeLadder(int lad, int step) {
+ if (ladder[lad][step]) return false;
+ if (lad>0 && ladder[lad-1][step]) return false;
+ if (lad tile;
+ private HashMap sharks;
+
+ Solution(String file) {
+ tile = new HashMap<>();
+ sharks = new HashMap<>();
+ if (file == null) {
+ setData();
+ } else {
+ readFromFile(file);
+ }
+ }
+
+ public int run() {
+ int iter = 0;
+ while (iter < 1000) {
+ iter ++;
+ ArrayList ss = new ArrayList<>(sharks.keySet());
+ ArrayList pp = new ArrayList<>(tile.keySet());
+ Collections.sort(ss);
+ for (int s : ss) {
+ nextPosition(s);
+ }
+ for (Position p : pp) {
+ State state = tile.get(p);
+ if (state.next()) {
+ tile.put(p, state);
+ } else {
+ tile.remove(p);
+ }
+ }
+ for (int s : ss) {
+ Position p = sharks.get(s).position;
+ if (tile.get(p) == null) {
+ tile.put(new Position(p.x,p.y), new State(s,k));
+ } else if (tile.get(p).shark == s) {
+ tile.put(new Position(p.x,p.y), new State(s,k));
+ } else {
+ sharks.remove(s);
+ }
+ }
+ if (sharks.size() < 2) return iter;
+ }
+
+ return -1;
+ }
+
+ private Position nextPosition(int s) {
+ Shark shark = sharks.get(s);
+ Position p = shark.position;
+ ArrayList next = shark.next.get(shark.direction-1);
+ boolean flag = false;
+ for (int d : next) {
+ shark.direction = d;
+ if (d == 1 && p.y>0) {
+ if (tile.get(new Position(p.x, p.y-1))!= null) continue;
+ p.y--;
+ flag = true; break;
+ } else if (d==2 && p.y0) {
+ if (tile.get(new Position(p.x-1, p.y))!= null) continue;
+ p.x--;
+ flag = true; break;
+ } else if (d==4 && p.x 0) {
+ if (tile.get(new Position(p.x, p.y-1)).shark != s) continue;
+ p.y--;
+ flag = true; break;
+ } else if (d == 2 && p.y < N - 1) {
+ if (tile.get(new Position(p.x, p.y+1)).shark != s) continue;
+ p.y++;
+ flag = true; break;
+ } else if (d == 3 && p.x > 0) {
+ if (tile.get(new Position(p.x-1, p.y)).shark != s) continue;
+ p.x--;
+ flag = true; break;
+ } else if (d == 4 && p.x < N - 1) {
+ if (tile.get(new Position(p.x+1, p.y)).shark != s) continue;
+ p.x++;
+ flag = true; break;
+ }
+ }
+ }
+ if (!flag) System.out.println("ERROR");
+ shark.position = p;
+ sharks.put(s, shark);
+ return new Position(p.x,p.y);
+ }
+
+ private void readFromFile(String filename) {
+ File file = new File(filename);
+
+ try {
+ FileReader reader = new FileReader(file);
+ BufferedReader breader = new BufferedReader(reader);
+
+ String line = breader.readLine();
+ String[] temp = line.split(" ");
+ N = Integer.parseInt(temp[0]);
+ M = Integer.parseInt(temp[1]);
+ k = Integer.parseInt(temp[2]);
+
+ for (int i=0; i dir = new ArrayList<>();
+ for (String t : temp) {
+ dir.add(Integer.parseInt(t));
+ }
+ s.next.add(dir);
+ }
+ sharks.put(i, s);
+ }
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void printTiles() {
+ int[][] tiles = new int[N][N];
+ tile.forEach((Position p, State s) -> {
+ tiles[p.y][p.x] = s.shark*10+s.smell;
+ });
+ sharks.forEach((Integer n, Shark s) -> {
+ tiles[s.position.y][s.position.x] = s.num*10+s.direction;
+ });
+ System.out.println("-----------------------------------------------");
+ for (int i=0; i> next;
+
+ Shark(int i, Position p) {
+ num = i;
+ position = p;
+ next = new ArrayList<>();
+ }
+}
+
+public class Position extends Object {
+ public int x;
+ public int y;
+
+ Position(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass()!=o.getClass()) return false;
+ Position p = (Position) o;
+ return (x==p.x)&&(y==p.y);
+ }
+
+ @Override
+ public int hashCode() {
+ return x*100+y;
+ }
+}
+
+public class State {
+ int shark;
+ int smell;
+
+ State(int shark, int smell) {
+ this.shark = shark;
+ this.smell = smell;
+ }
+
+ public boolean next() {
+ this.smell--;
+ if (smell > 0) {
+ return true;
+ }
+ return false;
+ }
+
+ public String toString() {
+ return shark+" "+smell;
+ }
+}
+```
+
+
+### 그 외 참고사항
+HashMap에서 Key를 찾을 때에,
+HashMap에 있는 key와 주어진 key를 비교할 때,
+hashcode()를 불러 먼저 비교하고, equals() 함수를 불러 true이면 같다고 판단한다.
diff --git a/source/diane/[baekjoon]1647.md b/source/diane/[baekjoon]1647.md
new file mode 100644
index 0000000..2264ded
--- /dev/null
+++ b/source/diane/[baekjoon]1647.md
@@ -0,0 +1,148 @@
+# Baekjoon 도시 분할 계획 문제
+
+- 도시 분할 계획
+ - https://www.acmicpc.net/problem/1647
+
+### 문제 이해하기
+N개의 집과 이 집들 사이를 잇는 M개의 길이 있는 마을이 있다.
+이 길은 양쪽 방향 모두로 다닐 수 있고, 길을 유지하는데 드는 유지비가 있다.
+이 마을을 두 개의 분리하려고 한다.
+각 마을에 있는 집들은 모두 연결되어야 하는데, 유지비가 최소가 되게끔만 길을 남기려고 한다.
+두 마을은 서로 다른 마을과는 연결되지 않는다.
+이 때 이 마을들의 길 유지비의 최솟값을 구하라.
+
+#### 입력
+- int N, M : 집의 개수, 길의 개수
+ - N : integer, such that 2 <= N <= 100,000
+ - M : integer, such that 1 <= M <= 1,000,000
+- int 3개 * M : 길이 연결하는 집의 번호 두 개, 그 길의 유지비
+ - 길의 유지비 C : integer, such that 1 <= C <= 1,000
+
+#### 출력
+- int : 남은 길의 유지비의 합의 최솟값
+
+### 문제 접근 방법
+길의 유지비를 최소로 하도록 마을을 둘로 나누는 것은,
+기존 마을을 MST로 만든 다음 가장 유지비가 큰 길을 없애서 나누면 원하는 조건대로 만들 수 있다.
+
+길의 갯수가 주어지고, Prim 알고리즘으로 풀기에는 각 집을 지나는 길을 찾는데 비용이 들어,
+이보다는 Kruskal로 푸는 것이 유리하다고 판단했다.
+
+먼저 모든 길을 유지비의 오름차순으로 정렬한다.
+유지비가 적은 길부터 차례대로, 길의 양쪽 집이 이미 연결되어 있는지 확인하고, 연결되어 있지 않으면 이 길을 선택한다.
+선택한 길이 N-1개라는 것은 MST를 만들었다는 것이기 때문에,
+이 때는 마지막으로 찾은 길을 포함하지 않고 (마을을 둘로 만들어야 하니까) 지금까지 선택한 길의 유지비의 합을 출력한다.
+
+길의 양쪽 집이 이미 연결되어 있는지를 확인할 때는,
+union-find 알고리즘을 사용하였다.
+
+
+### 구현 배경 지식
+- MST (Kruskal Algorithm)
+- Union-Find
+
+### 문제를 해결한 코드
+~~~java
+import java.util.*;
+
+public class Main {
+ private static int N;
+ private static int M;
+ private static int[] disjointSet;
+
+ public static void main(String args[]) {
+ Scanner sc = new Scanner(System.in);
+ N = sc.nextInt(); // vertex
+ M = sc.nextInt(); // edge
+
+ ArrayList paths = new ArrayList<>();
+ for (int i=0; i {
+ public int house1;
+ public int house2;
+ public int cost;
+
+ Path(int h1, int h2, int c) {
+ house1 = h1;
+ house2 = h2;
+ cost = c;
+ }
+
+ @Override
+ public int compareTo(Path b) {
+ return this.cost - b.cost;
+ }
+}
+~~~
+
+### 새로 알게 된 내용
+ArrayList의 remove 함수가 굉장히 시간적 cost가 큰 로직이라는 것을 새로 알게 되었다.
+초기에는 길을 선택할 때, 유지비로 정렬한 다음 리스트의 가장 첫 원소를 가져오고 삭제하고 이를 반복했는데,
+이 때는 시간 초과가 발생한다.
+이 후 길의 리스트를 돌면서 get으로 길을 가져오도록 변경하자, 알고리즘은 동일하지만, 시간 초과 없이 성공했다.
+이는 두 함수의 로직 차이에서 기인한다.
+remove 함수는 그 원소를 제거한 후에 그 뒤의 원소를 모두 한 칸 씩 앞으로 새로 저장하기 때문에 눈에 띄게 오래 걸리는 것이다.
+```java
+ public E get(int index) {
+ rangeCheck(index);
+
+ return elementData(index);
+ }
+
+ public E remove(int index) {
+ rangeCheck(index);
+
+ modCount++;
+ E oldValue = elementData(index);
+
+ int numMoved = size - index - 1;
+ if (numMoved > 0)
+ System.arraycopy(elementData, index+1, elementData, index,
+ numMoved);
+ elementData[--size] = null; // clear to let GC do its work
+
+ return oldValue;
+ }
+```
\ No newline at end of file
diff --git a/source/diane/[baekjoon]1931.md b/source/diane/[baekjoon]1931.md
new file mode 100644
index 0000000..0c9cc0d
--- /dev/null
+++ b/source/diane/[baekjoon]1931.md
@@ -0,0 +1,84 @@
+# Baekjoon 회의실 배정
+
+- 회의실 배정
+ - https://www.acmicpc.net/problem/1931
+
+
+### 문제 이해하기
+N개의 회의가 있는데, 회의실은 하나이다. 각 회의에 대해 시작시간과 끝나는 시간이 주어지고,
+회의가 겹치지 않게 회의실을 사용할 때 할 수 있는 회의의 최대 개수를 찾아라.
+회의는 중단되지 않으며, 회의가 끝남과 동시에 다른 회의가 시작될 수 있다.
+
+
+#### 입력
+- int N : 회의의 개수
+- int Start End : N번 반복되며, 각 회의의 시작시간과 끝시간
+
+
+#### 출력
+- int : 할 수 있는 회의의 최대 개수
+
+
+### 문제 접근 방법
+회의실에서 어떤 회의가 진행된다면, 그 회의가 빨리 끝날수록 그 회의실에서 더 많은 회의를 할 가능성이 증가한다.
+따라서 지금 회의실에서 할 수 있는 회의 중 가장 빨리 끝나는 회의를 해야 한다.
+
+
+### 구현 배경 지식
+- Greedy Algorithm
+
+
+### 문제를 해결한 코드
+~~~java
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Scanner;
+
+public class Main {
+ public static void main(String args[]) {
+ Scanner sc = new Scanner(System.in);
+ ArrayList meetings = new ArrayList<>();
+
+ int count = sc.nextInt();
+ for (int i=0; i= time) {
+ number++;
+ time = meeting.end;
+ }
+ }
+
+ System.out.println(number);
+ }
+}
+
+class Meeting implements Comparable {
+ public int start;
+ public int end;
+
+ public Meeting(int start, int end) {
+ this.start = start;
+ this.end = end;
+ }
+
+ @Override
+ public int compareTo(Meeting m) {
+ if (end == m.end)
+ return start - m.start;
+ return end - m.end;
+ }
+
+ @Override
+ public String toString() {
+ return "Meeting{" + start + "~" + end + '}';
+ }
+}
+~~~
\ No newline at end of file
diff --git a/source/diane/[baekjoon]2042.md b/source/diane/[baekjoon]2042.md
new file mode 100644
index 0000000..5ca7ae0
--- /dev/null
+++ b/source/diane/[baekjoon]2042.md
@@ -0,0 +1,116 @@
+# Baekjoon 구간 합 구하기
+
+- 구간 합 구하기
+ - https://www.acmicpc.net/problem/2042
+
+### 문제 이해하기
+N개의 숫자가 주어져 있다. 이 N개의 숫자를 가지고, 이 중 특정한 수의 값을 바꾸거나, 이 중 특정 구간의 수들의 합을 구하는 작업을 하려고 한다.
+수의 값을 바꾸고, 구간의 합을 구하는 작업이 들어올 때, 이를 작업이 들어올 때마다 실행하며, 합을 구하면 그 값을 반환해라.
+
+#### 입력
+- int N M K : 주어진 숫자의 갯수, 수의 변경이 일어나는 횟수, 구간의 합을 구하는 횟수
+- long NUM : N번 반복하면서 주어진 숫자를 입력
+- int A B (long) C : (M+K)번 반복
+ - A==1 : 수의 변경, B번째 수를 C의 값으로 바꾸어야 한다.
+ - A==2 : 구간의 합, B번째 수부터 C번째 수까지의 합을 구하고 출력한다.
+
+#### 출력
+- int : K번 반복하면서, 구간의 합을 출력
+
+### 문제 접근 방법
+주어진 숫자 배열로 먼저 segment tree를 만든다.
+이후로는 숫자의 값을 바꿀 때는 tree의 root부터 값의 변화량을 적용시키면서, 해당 index의 leaf의 값까지 변화시킨다.
+구간의 합을 구할 때는 tree의 root부터 검색하면서, 원하는 구간에 해당하는 node의 값을 더하여 합을 구한다.
+
+
+### 구현 배경 지식
+- Segment Tree
+
+주어진 숫자의 갯수가 N, 수의 변경이 M번, 구간 합을 K번 구한다고 가정하자.
+
+| 작업 | 일반 | segment tree |
+|-----|:----:|:------------:|
+|값 변경하기|O(1)|O(logN)|
+|구간 합 구하기|O(N)|O(logN)|
+|모든 작업|O(NK)|O((M+K)logN)|
+
+작업의 수(K)가 많을수록, 주어진 숫자의 갯수(N)이 많을수록, segment tree가 유리하다.
+
+
+### 문제를 해결한 코드
+~~~java
+import java.util.Scanner;
+
+public class Main {
+ private static long[] array;
+ private static long[] segTree;
+
+ public static void main(String args[]) throws Exception {
+ Scanner sc = new Scanner(System.in);
+
+ int N = sc.nextInt();
+ int M = sc.nextInt();
+ int K = sc.nextInt();
+
+ array = new long[N];
+ for (int i=0; i end) return;
+
+ segTree[node] += diff;
+ if (start == end) return;
+ int mid = (start+end)/2;
+ updateSegTree(index, diff, node*2, start, mid);
+ updateSegTree(index, diff, node*2+1, mid+1, end);
+ }
+
+ private static long sumSegTree(int node, int start, int end, int left, int right) {
+ if (left > end || right < start) return 0;
+ if (left <= start && end <= right) return segTree[node];
+ int mid = (start+end)/2;
+ return sumSegTree(node*2, start, mid, left, right) + sumSegTree(node*2+1, mid+1, end, left, right);
+ }
+}
+~~~
\ No newline at end of file
diff --git a/source/diane/[baekjoon]2583.md b/source/diane/[baekjoon]2583.md
new file mode 100644
index 0000000..e377d1b
--- /dev/null
+++ b/source/diane/[baekjoon]2583.md
@@ -0,0 +1,121 @@
+# Baekjoon 영역 구하기 문제
+
+- 영역 구하기
+ - https://www.acmicpc.net/problem/2583
+
+### 문제 이해하기
+MxN 크기의 모눈종이가 있다.
+이 모눈종이에 눈금을 맞추어 k개의 직사각형을 그리면,
+모눈종이가 이 직사각형의 내부를 제외한 나머지 부분으로 나뉘게 된다.
+이 때 만들어진 나머지 영역이 몇 개이고, 그 넓이는 각각 얼마인지 구하라.
+
+#### 입력
+- int M, N, K : 모눈종이의 세로 길이, 가로 길이, 그려진 직사각형의 개수
+ - 모두 100 이하의 자연수
+- int 4개 * k : k개의 직사각형의 왼쪽 아래 꼭지점의 좌표와 오른쪽 위 꼭지점의 좌표
+
+#### 출력
+- int : 분리된 영역의 개수
+- int 여러 개 : 각 영역의 넓이 (띄어쓰기로 구분)
+
+### 문제 접근 방법
+모눈종이의 각 칸은 아래 두가지로 구분한다.
+- visited = true : 직사각형의 내부로, 문제에서 필요 없는 부분이다.
+ 또한, 이미 검사한 나머지 부분으로, 이미 검사했으니 다시 검사할 필요가 없는 부분도 이렇게 나타낸다.
+- visited = false : 직사각형에 의해 생긴 나머지 부분으로, 앞으로 검사해야 할 부분이다.
+
+문제를 해결하기 위해 사용한 방법은 아래와 같다.
+1. 모눈종이에서 아직 검사하지 않은 나머지 부분을 찾는다.
+2. 찾은 나머지 부분이 포함된 나머지 영역을 찾고, 그 넓이를 구한다.
+ - 검사하지 않은 나머지 부분과 연결된 검사하지 않은 나머지 부분을 찾는다.
+ - 새로 찾은 검사하지 않은 나머지 부분에 대하여 이를 반복한다.
+ - 더 이상 연결된 검사하지 않은 나머지 부분이 없다면, 이 부분이 포함된 영역은 모두 찾은 것이기 때문에 넓이를 기록하고 종료한다.
+3. 1-2번을 더 이상 검사하지 않은 나머지 부분이 없을 때까지 반복한다.
+
+
+### 구현 배경 지식
+BFS
+
+### 문제를 해결한 코드
+~~~java
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Scanner;
+
+public class Main {
+
+ public static void main(String args[]) {
+ Scanner sc = new Scanner(System.in);
+ int m = sc.nextInt();
+ int n = sc.nextInt();
+ int k = sc.nextInt();
+ boolean[][] matrix = new boolean[n][m];
+ ArrayList width = new ArrayList<>();
+
+ for (int c=0; c queue = new ArrayList<>();
+ for (int i=0; i x).toArray();
+ int x = position[0];
+ int y = position[1];
+ if (matrix[x][y]) continue;
+
+ matrix[x][y] = true;
+ count++;
+
+ if (x-1>=0 && !matrix[x-1][y]) queue.add(new Integer[] {x-1,y});
+ if (x+1=0 && !matrix[x][y-1]) queue.add(new Integer[] {x,y-1});
+ if (y+1 cups;
+
+ public static void main(String args[]) {
+ Scanner sc = new Scanner(System.in);
+ int sugar = sc.nextInt();
+
+ cups = new HashMap<>();
+ cups.put(3,1);
+ cups.put(5,1);
+ cups.put(1,-1);
+ cups.put(2,-1);
+ cups.put(4,-1);
+ cups.put(6,2);
+
+ System.out.println(calculate(sugar));
+ }
+
+ private static int calculate(int sugar) {
+ if (cups.containsKey(sugar)) return cups.get(sugar);
+
+ int cup = -1;
+ int cup1 = calculate(sugar-5);
+ int cup2 = calculate(sugar-3);
+
+ if (cup1 != -1) {
+ if (cup2 != -1) {
+ cup = (cup1 > cup2? cup2:cup1)+1;
+ } else {
+ cup = cup1+1;
+ }
+ } else if (cup2 != -1) {
+ cup = cup2+1;
+ }
+
+ cups.put(sugar, cup);
+
+ return cup;
+ }
+}
+~~~
\ No newline at end of file
diff --git a/source/diane/[baekjoon]4256.md b/source/diane/[baekjoon]4256.md
new file mode 100644
index 0000000..503437e
--- /dev/null
+++ b/source/diane/[baekjoon]4256.md
@@ -0,0 +1,135 @@
+# Baekjoon 트리 문제
+
+- 트리
+ - https://www.acmicpc.net/problem/4256
+
+### 문제 이해하기
+어떤 이진 트리가 주어진다. 이 이진 트리는 노드 n개로 이루어져있고, 각 노드는 1부터 n까지의 유일한 번호를 가지고 있다.
+이 이진 트리를 전위 순회(preorder)한 결과와 중위 순회(inorder)한 결과가 주어졌을 때,
+후위 순회(postorder)한 결과를 구하여라.
+
+#### 입력
+- int T : 테스트케이스 개수
+ - 이 아래 입력은 테스트케이스 개수만큼 반복됨
+- int n : 이진 트리의 노드 갯수
+- int o1, o2, ... , on : 이진 트리를 전위 순회한 결과
+- int o1, o2, ... , on : 이진 트리를 중위 순회한 결과
+
+#### 출력
+- int o1, o2, ... , on : 이진 트리를 후위 순회한 결과 (테스트케이스 개수 만큼)
+
+### 문제 접근 방법
+주어진 전위 순회 결과와 중위 순회 결과를 가지고 이진 트리를 복원한 다음 이 이진 트리를 후위 순회한 결과를 출력한다.
+
+먼저, 전위 순회 결과와 중위 순회 결과로 이진 트리를 복원해야 한다.
+전위 순회는 root 노드를 먼저 출력하고, 그 노드의 왼쪽 자식 노드로 가 전위 순회하고, 이후에 오른쪽 자식 노드로 가 전위 순회한다.
+따라서 전위 순회 결과는 언제나 (root 노드) (그 노드의 왼쪽 자식 노드가 root인 트리를 전위 순회한 결과) (그 노드의 오른쪽 자식 노드가 root인 트리를 전위 순회한 결과)이다.
+중위 순회는 왼쪽 자식 노드를 중위 순회한 결과를 출력하고, 그 노드를 출력한 다음, 오른쪽 자식 노드를 중위 순회한 결과를 출력한다.
+따라서 중위 순회 결과는 언제나 (그 노드의 왼쪽 자식 노드가 root인 트리를 중위 순회한 결과) (root 노드) (그 노드의 오른쪽 자식 노드가 root인 트리를 중위 순회한 결과)이다.
+
+이진 트리를 복원할 때는 분할 정복을 사용한다.
+전위 순회 결과를 통해 트리의 root 노드를 찾은 다음, 그 root 노드를 중위 순회 결과에서 찾으면, 그 노드를 중심으로 왼쪽에 위치한 모든 노드와 오른쪽에 위치한 모든 노드를 찾을 수 있다.
+전위 순회 결과에서 root 노드 이후에는 그 노드를 중심으로 왼쪽에 위치한 모든 노드가 나오고 그 뒤에 오른쪽에 위치한 모든 노드가 나온다.
+따라서 중위 순위 결과에서 찾을 수 있는 왼쪽에 위치한 모든 노드를 대상으로, 왼쪽의 이진 트리를 복원하고,
+그 후에 오른쪽에 위치한 모든 노드를 대상으로 오른쪽의 이진 트리를 복원하는 과정을 반복할 것이다.
+즉 root 노드를 찾은 후에, 그 root 노드의 왼쪽 자식을 root로 하는 이진 트리를 만들고, 오른쪽 자식을 root로 하는 이진 트리를 만드는 것이다.
+전체의 이진 트리를 만드는 것이 기본 문제(problem)이고, root 노드의 왼쪽 또는 오른쪽 자식 노드를 root로 하는 이진 트리를 만드는 것이 하위 문제(sub problem)인 것이다.
+
+이 과정에서 전위 순회 결과는 앞에서부터 순서대로 출력되므로, queue를 사용하기에 알맞으며,
+중위 순회 결과는 하위 문제로 갈 때, root 노드를 기준으로 왼쪽 부분과 오른쪽 부분으로 분할되게 된다.
+
+이진 트리가 전부 만들어지면, 이제 이를 후위 순회하며 그 결과를 출력한다.
+후위 순회는 root 노드에서 먼저 왼쪽 자식 노드를 root로 하는 트리에서 후위 순회를 하고, 이후에 오른쪽 자식 노드를 root로 하는 트리에서 후위 순회를 한 다음에 root 노드를 출력한다.
+
+
+
+### 구현 배경 지식
+- 트리와 이진 트리
+- 이진 트리의 순회 방법
+ - preorder : root -> left -> right
+ - inorder : left -> root -> right
+ - postorder : left -> right -> root
+
+- 분할 정복 divide and conquer
+
+### 문제를 해결한 코드
+~~~java
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Scanner;
+
+public class Main {
+
+ private static Queue preorder;
+ private static ArrayList inorder;
+ private static int size;
+
+ public static void main(String args[]) {
+ Scanner sc = new Scanner(System.in);
+ int testcase = sc.nextInt();
+
+ for (int t=0; t();
+ inorder = new ArrayList<>();
+ for (int i=0; i in1) {
+ Node left = makeTree(in1, index);
+ node.left = left;
+ }
+ if (index < in2-1) {
+ Node right = makeTree(index+1, in2);
+ node.right = right;
+ }
+
+ return node;
+ }
+
+ private static void printPostOrder(Node n) {
+ if (n == null) return;
+ if (n.left != null) {
+ printPostOrder(n.left);
+ }
+ if (n.right != null) {
+ printPostOrder(n.right);
+ }
+ System.out.print(n.index+" ");
+ }
+}
+
+class Node {
+ public Node left;
+ public Node right;
+ public int index;
+
+ public Node(int n) {
+ index = n; left = null; right = null;
+ }
+
+ @Override
+ public String toString() {
+ int l = (left==null)? 0 : left.index;
+ int r = (right==null)? 0 : right.index;
+ return "Node{" + index+" : "+l+" "+r+"}";
+ }
+}
+~~~
\ No newline at end of file
diff --git a/source/diane/[baekjoon]6549-2.md b/source/diane/[baekjoon]6549-2.md
new file mode 100644
index 0000000..cc775fb
--- /dev/null
+++ b/source/diane/[baekjoon]6549-2.md
@@ -0,0 +1,181 @@
+# Baekjoon 히스토그램에서 가장 큰 직사각형
+
+- 히스토그램에서 가장 큰 직사각형
+ - https://www.acmicpc.net/problem/6549
+
+### 문제 이해하기
+히스토그램은 직사각형 여러 개가 아래쪽으로 정렬되어 있는 도형으로, 이 직사각형은 모두 같은 너비를 가지고 있지만 높이는 서로 다르다.
+이 때 이 히스토그램에서 그릴 수 있는 직사각형 중 가장 넓이가 큰 직사각형의 넓이를 구하여라.
+
+#### 입력
+- int N A1 A2 ... AN : 직사각형의 수와 높이 (여러 벌)
+ - N : 직사각형의 갯수
+ - A1 ... AN : 직사각형의 높이
+- 0 : 입력의 끝
+
+#### 출력
+- int : 히스토그램에서 가장 넓이가 큰 직사각형의 넓이 (입력의 수 만큼)
+
+### 문제 접근 방법
+먼저 주어진 히스토그램으로 segment tree를 만든다.
+이 때 각 노드는 히스토그램에서 그 노드의 구간만을 보았을 때, 그 너비로 만들 수 있는 가장 큰 직사각형의 정보를 담을 것이다.
+따라서, 그 너비(number)와 가장 큰 직사각형의 높이(height), 그리고 이 높이를 가지는 직사각형의 인덱스(index) 정보를 가진다.
+두 노드의 부모 노드는, 이 두 노드가 가진 구간에서 그 너비로 만들 수 있는 가장 큰 직사각형의 정보를 담아야 하기 때문에,
+너비는 자식 노드 둘의 너비의 합이고, 높이는 두 자식 노드가 가진 높이 중에 작은 것, 인덱스는 더 작은 높이를 가진 자식 노드가 가졌던 인덱스를 가진다.
+
+segment tree가 다 만들어지면, 이를 이용해서 전체 히스토그램에서의 가장 큰 직사각형을 찾을 것이다.
+가장 간단한 방법은 완전 탐색이지만, 이는 O(N^2)의 시간 복잡도를 가지므로 주어진 시간 안에 찾지 못할 수도 있다.
+따라서 Divide and Conquer 방식을 사용한다.
+먼저 전체 너비로 만들 수 있는 가장 큰 직사각형의 넓이를 구한다.
+이 직사각형의 높이는 이 너비에 있는 각 직사각형의 높이 중 가장 작은 것이다.
+이 가장 작은 직사각형을 중심으로 그 왼쪽 구간과 오른쪽 구간으로 나누어 그 넓이를 구하고,
+또 이 때 가장 작은 직사각형을 찾아 구간을 나누어 넓이를 구하는 과정을 반복한다.
+가장 작은 높이가 포함되어 있다면, 현재 구한 너비가 가장 큰 너비이기 때문에, 이 높이의 직사각형을 제하고 양 옆으로 구간을 나누는 것이다.
+이렇게 구한 직사각형의 넓이 중 가장 큰 것이, 전체 히스토그램에서 그릴 수 있는 가장 넓이가 큰 직사각형이다.
+
+
+### 구현 배경 지식
+- Segment Tree + Divide and Conquer
+
+### 문제를 해결한 코드
+~~~java
+import java.util.Scanner;
+
+public class Main {
+ private static long[] array;
+ private static Node[] segTree;
+
+ public static void main(String args[]) {
+ Scanner sc = new Scanner(System.in);
+ String testCase = null;
+
+ while (true) {
+ testCase = sc.nextLine();
+ if (testCase.equals("0")) break;
+
+ array = convert(testCase);
+ System.out.println(solution());
+ }
+
+ }
+
+ private static long solution() {
+ segTree = makeSegTree();
+ init(1,0,array.length-1);
+
+/* 완전 탐색으로 접근하여 시간 초과가 난 풀이
+ int maxArea = Integer.MIN_VALUE;
+ for (int i=array.length-1; i>0; i--) {
+ for (int j=0; j maxArea) maxArea = area;
+ }
+ }
+*/
+ return getBiggerArea(0, array.length-1);
+ }
+
+ private static Node[] makeSegTree() {
+ double height = Math.ceil(Math.log(array.length)/Math.log(2.0));
+ int treeSize = (int) Math.pow(2.0, height+1);
+ return new Node[treeSize];
+ }
+
+ private static Node init(int node, int start, int end) {
+ if (start == end) return segTree[node] = new Node(array[start], 1, start);
+ int mid = (start+end)/2;
+ Node n1 = init(node*2, start, mid);
+ Node n2 = init(node*2+1, mid+1, end);
+ long height = n1.height;
+ int index = n1.index;
+ if (n1.height > n2.height) {
+ height = n2.height; index = n2.index;
+ }
+ return segTree[node] = new Node(height, n1.number+n2.number, index);
+ }
+
+ private static long getBiggerArea(int start, int end) {
+ Node node = findArea(1,0, array.length-1, start, end);
+ long area = node.area;
+ if (node.index == -1) return area;
+ if (start < node.index) {
+ long temp = getBiggerArea(start, node.index-1);
+ if (temp > area) area = temp;
+ }
+ if (end > node.index) {
+ long temp = getBiggerArea(node.index+1, end);
+ if (temp > area) area = temp;
+ }
+ return area;
+ }
+
+ private static Node findArea(int node, int start, int end, int left, int right) {
+ if (left > end || right < start) return new Node(0,0, -1);
+ if (left <= start && end <= right) {
+ return segTree[node]==null? new Node(0,0, -1):segTree[node];
+ }
+ int mid = (start+end)/2;
+ Node n1 = findArea(node*2, start, mid, left, right);
+ Node n2 = findArea(node*2+1, mid+1, end, left, right);
+ long height = n1.height;
+ int index = n1.index;
+ if (n1.height == 0) {
+ if (n2.height == 0) {
+ height = 0;
+ if (n1.index == -1) index = n2.index;
+ else if (n2.index == -1) index = n1.index;
+ else index = (n1.index>n2.index)?n2.index:n1.index;
+ } else if (n1.index == -1){
+ height = n2.height; index = n2.index;
+ } else {
+ height = n1.height; index = n1.index;
+ }
+ } else if (n2.index == -1) {
+ height = n1.height; index = n1.index;
+ } else if (n2.height == 0) {
+ height = n2.height; index = n2.index;
+ } else if (n1.height > n2.height){
+ height = n2.height; index = n2.index;
+ }
+ return new Node(height, n1.number+n2.number, index);
+ }
+
+ private static long[] convert(String array) {
+ String[] temp = array.split(" ");
+ long[] result = new long[temp.length-1];
+ for (int i=1; i stack = new Stack<>(); // stack에는 현재보다 작은 것들만 남아있을 것
+ int size = array.length;
+
+ long area = Long.MIN_VALUE;
+ for (int i=0; iheight) {
+ Element oldElm = stack.pop();
+ int width = (stack.empty()? i: i-stack.peek().index-1);
+ long newArea = width*oldElm.height;
+ if (area < newArea) area = newArea;
+ }
+ stack.push(new Element(height, i));
+ }
+
+ while(!stack.empty()) {
+ Element temp = stack.pop();
+ int width = (stack.empty()? size: size-stack.peek().index-1);
+ long newArea = width*temp.height;
+ if (area < newArea) area = newArea;
+ }
+
+ System.out.println(area);
+ }
+
+ }
+
+ private static long[] convert(String array) {
+ String[] temp = array.split(" ");
+ long[] result = new long[temp.length-1];
+ for (int i=1; i> networks = new ArrayList<>();
+
+ while (checkFlag()) {
+ int start = getFirstRemainder();
+ System.out.println(start);
+ Set network = dfs(start);
+ networks.add(network);
+ }
+ return networks.size();
+ }
+
+ private boolean checkFlag() {
+ boolean result = true;
+ int idx = 0;
+ while (result) {
+ if (idx >= flags.length) break;
+ result = result && flags[idx];
+ idx++;
+ }
+ return !result;
+ }
+
+ private int getFirstRemainder() {
+ for (int i=0; i dfs(int start) {
+ Set network = new HashSet<>();
+
+ flags[start] = true;
+ for (int i=0; i> disks;
+ private MinHeap remainings;
+
+ public Solution() {
+ disks = new HashMap<>();
+ remainings = new MinHeap();
+ }
+
+ public int solution(int[][] jobs) {
+ int time = 0;
+ int runtime = 0;
+ int number = jobs.length;
+
+ for (int[] disk : jobs) {
+ ArrayList list = new ArrayList<>();
+ if (disks.containsKey(disk[0])) {
+ list = disks.get(disk[0]);
+ }
+ list.add(Arrays.stream(disk).boxed().toArray(Integer[]::new));
+ disks.put(disk[0], list);
+ }
+
+ ArrayList times = new ArrayList<>(disks.keySet());
+ Collections.sort(times);
+ while (times.size() > 0 || remainings.size() > 0) {
+ // 이 시간에 사용할 수 있는 disk 넣
+ while (times.size() > 0 && times.get(0) <= time) {
+ for (Integer[] item : disks.get(times.get(0))) {
+ remainings.insert(item);
+ }
+ times.remove(0);
+ if (times.size() < 1) break;
+ }
+
+ // 만약 이 시간에 할 수 있는 것이 없다면
+ if (remainings.size()<1) {
+ time++;
+ continue;
+ }
+
+ Integer[] item = remainings.delete();
+ time = time + item[1];
+ runtime = runtime + (time-item[0]);
+ }
+
+ System.out.println("Total Time : "+time);
+ runtime = runtime / number;
+
+ return runtime;
+ }
+}
+
+class MinHeap {
+ private ArrayList heap;
+
+ public MinHeap() {
+ heap = new ArrayList<>();
+ heap.add(new Integer[] {0,0}); // index 0 added (not use index 0)
+ }
+
+ public void insert(Integer[] v) {
+// Integer[] value = Arrays.stream(v).boxed().toArray(Integer[]::new);
+ heap.add(v);
+
+ int p = heap.size()-1;
+ while (p>1 && heap.get(p/2)[1]>heap.get(p)[1]) {
+ Integer[] temp = heap.get(p/2);
+ heap.set(p/2, heap.get(p));
+ heap.set(p, temp);
+ p = p/2;
+ }
+ }
+
+ public Integer[] delete() {
+ if (heap.size() < 2) {
+ return new Integer[] {0,0};
+ }
+
+ Integer[] deleteItem = heap.get(1);
+ heap.set(1, heap.get(heap.size()-1));
+ heap.remove(heap.size()-1);
+
+ int p = 1;
+ while ((p*2) < heap.size()) {
+ Integer[] min = heap.get(p*2);
+ int minp = p*2;
+ if ((minp+1 < heap.size()) && (min[1] > heap.get(minp+1)[1])) {
+ min = heap.get(minp+1);
+ minp = minp+1;
+ }
+ if (heap.get(p)[1] < min[1]) break;
+
+ heap.set(minp, heap.get(p));
+ heap.set(p, min);
+ p = minp;
+ }
+
+ return deleteItem;
+ }
+
+ public int size() {
+ return heap.size()-1;
+ }
+
+ public String toString() {
+ String line = "";
+ return line;
+ }
+}
+~~~
+
diff --git a/source/diane/[programmers]42628.md b/source/diane/[programmers]42628.md
new file mode 100644
index 0000000..5b61947
--- /dev/null
+++ b/source/diane/[programmers]42628.md
@@ -0,0 +1,85 @@
+# Programmers 이중우선순위큐 문제
+
+- 이중우선순위큐
+ - https://programmers.co.kr/learn/courses/30/lessons/42628
+
+### 문제 이해하기
+이중우선순위큐는 연산의 목록을 받는다.
+그 연산은 세 가지 종류로, 큐에 숫자를 추가하거나, 큐에서 최댓값 또는 최솟값을 제거한다.
+이중우선순위큐가 이 연산을 모두 실행한 후의 큐의 최댓값과 최솟값을, 큐가 비어있다면 0,0을 반환한다.
+모든 연산은 숫자 하나만을 대상으로 하고, 만약 큐가 비어있는데 값을 삭제해야한다면, 그 연산은 무시한다.
+
+#### 입력
+- String[] operations : 연산의 목록
+ - 각 연산은 첫 글자로 알파벳 I 또는 D가 오고, 띄어쓰기 후 I라면 모든 숫자, D라면 1 또는 -1이 온다.
+ - 연산의 의미
+ - I 숫자 : 큐에 이 숫자를 추가
+ - D 1 : 큐에서 최댓값 삭제
+ - D -1 : 큐에서 최솟값 삭제
+
+#### 출력
+- int[] : 크기 2의 숫자 배열로, 첫 원소는 이 큐의 최댓값, 마지막 원소는 이 큐의 최소값.
+ - 만약 큐가 비어있다면, [0,0]을 반환.
+
+### 문제 접근 방법
+"이중우선순위큐"이지만, FIFO과는 관계가 없다.
+또한 원소들의 순서는 전혀 관계없고, 그때그때 최솟값과 최댓값만 알면 되기 때문에,
+자료구조로 minHeap과 maxHeap을 동시에 사용했다.
+
+모든 연산에 대해 순서대로 아래 행동을 반복한다.
+- I 숫자 : minHeap과 maxHeap에 이 숫자를 추가한다.
+- D 1 : maxHeap에서 최댓값을 제거하고, minHeap에서 동일한 값을 제거한다.
+- D -1 : minHeap에서 최솟값을 제거하고, maxHeap에서 동일한 값을 제거한다.
+모든 연산을 수행했다면, maxHeap에서 최댓값을, minHeap에서 최솟값을 찾아 반환한다.
+만약 힙의 크기가 0이라면, 최댓값과 최솟값으로 0을 반환한다.
+
+### 구현 배경 지식
+MinHeap, MaxHeap
+
+### 문제를 해결한 코드
+~~~java
+import java.util.Collections;
+import java.util.PriorityQueue;
+
+public class Solution {
+ PriorityQueue minHeap;
+ PriorityQueue maxHeap;
+
+ public Solution() {
+ minHeap = new PriorityQueue<>();
+ maxHeap = new PriorityQueue<>(Collections.reverseOrder());
+ }
+
+ public int[] solution(String[] operations) throws Exception {
+ int[] answer = new int[2];
+
+ for (String operation : operations) {
+ String[] commands = operation.split(" ");
+ if (commands[0].equals("I")) {
+ int number = Integer.parseInt(commands[1]);
+ minHeap.add(number);
+ maxHeap.add(number);
+ } else if (commands[0].equals("D")) {
+ if (minHeap.size() < 1) continue;
+ if (commands[1].equals("1")) {
+ int number = maxHeap.poll();
+ minHeap.remove(number);
+ } else if (commands[1].equals("-1")) {
+ int number = minHeap.poll();
+ maxHeap.remove(number);
+ } else {
+ throw new Exception("Invalid operation : "+operation);
+ }
+ } else {
+ throw new Exception("Invalid operation : "+operation);
+ }
+ }
+ if (maxHeap.size() != 0) {
+ answer[0] = maxHeap.peek();
+ answer[1] = minHeap.peek();
+ }
+
+ return answer;
+ }
+}
+~~~
\ No newline at end of file
diff --git a/source/diane/[programmers]42862.md b/source/diane/[programmers]42862.md
new file mode 100644
index 0000000..a07a970
--- /dev/null
+++ b/source/diane/[programmers]42862.md
@@ -0,0 +1,64 @@
+# Programmers 체육복 문제
+
+- 체육복
+ - https://programmers.co.kr/learn/courses/30/lessons/42862
+
+### 문제 이해하기
+학생들은 기본으로 체육복을 하나씩 가지고 있다. 그런데 점심시간에 도둑이 들어, 일부 학생이 체육복을 도난 당했다.
+따라서 여벌 체육복을 가진 학생들이 체육복이 없는 학생에게 체육복을 빌려주려고 한다.
+여벌 체육복이 없는 학생은 자신의 체육복을 입어야 하기 때문에, 체육복을 빌려줄 수 없으며, 여벌의 체육복이 있었더라도 자신의 체육복을 도난 당했다면 자신의 여벌 체육복을 빌려줄 수 없다.
+학생들은 모두 체격이 다르기 때문에, 체격 순으로 매겨진 번호로 자신의 바로 앞번호나 바로 뒷번호의 학생의 체육복만 입을 수 있다.
+가능한 많은 학생들이 체육복을 입게 한다면, 총 몇 명의 학생이 체육복을 입을 수 있는지를 구하여라.
+
+#### 입력
+- int n : 전체 학생의 수 (번호는 1번부터 n번까지, 중복되지 않는다.)
+- int[] lost : 체육복을 도난당한 학생들의 번호가 담긴 배열 (중복 없음)
+- int[] reserve : 여벌의 체육복이 있는 학생들의 번호가 담긴 배열 (중복 없음)
+
+#### 출력
+- int : 체육복을 입을 수 있는 가장 많은 학생 수
+
+### 문제 접근 방법
+체육복이 없는 학생의 번호를 작은 순부터 탐색하면서,
+여벌의 체육복을 가진 학생이 앞번호에 있으면 그 학생에게, 없으면 그 뒷학생에게 체육복을 빌린다고 가정한다.
+만약 양쪽 번호 모두 여벌의 체육복이 없으면 체육복이 없는 학생은 체육복을 빌리지 못한다.
+
+여벌의 체육복이 있더라도, 자신의 체육복을 도난당한 학생은 체육복을 빌려줄 수 없기 떄문에,
+이 경우는 사전에 제거한다.
+
+### 구현 배경 지식
+Greedy Algorithm
+
+### 문제를 해결한 코드
+~~~java
+import java.util.ArrayList;
+
+public class Solution {
+ public int solution(int n, int[] lost, int[] reserve) {
+ int answer = n - lost.length;
+ ArrayList more = new ArrayList<>();
+ ArrayList no = new ArrayList<>();
+
+ for (int i : reserve) more.add(i);
+ for (int i : lost) {
+ if (more.contains(i)) {
+ more.remove((Integer)i);
+ answer++;
+ } else {
+ no.add(i);
+ }
+ }
+ for (int i : no) {
+ if (more.contains(i-1)) {
+ more.remove((Integer)(i-1));
+ answer++;
+ } else if (more.contains(i+1)) {
+ more.remove((Integer)(i+1));
+ answer++;
+ }
+ }
+
+ return answer;
+ }
+}
+~~~
diff --git a/source/diane/[programmers]43164.md b/source/diane/[programmers]43164.md
new file mode 100644
index 0000000..975d8eb
--- /dev/null
+++ b/source/diane/[programmers]43164.md
@@ -0,0 +1,109 @@
+# Programmers 여행경로 문제
+
+- 여행경로
+ - https://programmers.co.kr/learn/courses/30/lessons/43164
+
+### 문제 이해하기
+출발 도시와 도착 도시가 고정된 항공권 목록이 주어진다.
+이 항공권을 모두 이용하여 여행경로를 짜야한다.
+첫 출발지는 "ICN"이며, 항공권을 모두 사용할 수 없는 경우는 주어지지 않는다.
+만약 가능한 여행경로가 여러 개라면, 알파벳 순으로 앞서는 경로를 구한다.
+
+#### 입력
+- String[][] tickets : 항공권의 목록
+ - 모든 ticket은 길이 2의 String 배열로 이루어져 있다
+ - ticket의 첫번째 원소는 출발지, 두번째 원소는 도착지이다
+
+#### 출력
+- String[] : "ICN"으로부터 시작하는 여행 경로의 도시 목록
+
+### 문제 접근 방법
+모든 가능성을 전부 탐색하면서 항공권을 모두 사용하는 여행경로를 찾는다.
+그 방법은 다음과 같다.
+1. 현재 위치한 도시를 찾는다. (처음은 ICN)
+2. 현재 위치한 도시에서 갈 수 있는 모든 도시를 찾는다.
+3. 각 다음 도시에 대해 그 도시를 현재의 도시로 하여 이 전체 과정을 반복한다. 즉, 그 도시로 이동할 경우 가능한 여행경로 중 가장 좋은 경로를 찾는다.
+4. 과정 3에서 찾은 각 다음 도시의 가장 좋은 여행경로 중 조건에 맞는 여행경로를 찾는다.
+
+여기서 조건이 맞다는 것은 아래와 같다.
+1. 이 도시에서 시작하는 여행경로 중 가장 긴 경로일 것.
+한 여행경로보다 더 긴 여행경로가 있다는 것은, 그 여행경로가 충분히 많은 도시를 여행하지 않았다는 뜻이다.
+또한, 문제의 조건에서 모든 도시를 여행하지 못하는 경우는 없다고 했기 때문에 (즉, 그런 여행경로가 없는 경우를 판단할 필요가 없기 때문에), 모든 항공권을 다 사용한 여행경로는 필연적으로 가장 길 것이다.
+2. 만약 여러 여행경로의 길이가 같다면, 이 중 알파벳 순으로 앞서는 것을 선택한다.
+
+### 구현 배경 지식
+DFS, Backtracking
+
+### 문제를 해결한 코드
+~~~java
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class Solution {
+
+ public String[] solution(String[][] tickets) {
+ // tickets 정보를 HashMap에 넣는다
+ HashMap> list = new HashMap<>();
+ for (String[] ticket : tickets) {
+ ArrayList dest = new ArrayList<>();
+ if (list.containsKey(ticket[0])) {
+ dest = list.get(ticket[0]);
+ }
+ dest.add(ticket[1]);
+ list.put(ticket[0], dest);
+ }
+
+ // ICN을 시작으로 여행경로 찾기
+ ArrayList path = new ArrayList<>();
+ path.add("ICN");
+ path = findPath(path, list);
+
+ return path.toArray(new String[path.size()]);
+ }
+
+ private ArrayList findPath(ArrayList path, HashMap> list) {
+ ArrayList finalpath = path;
+ String depart = path.get(path.size()-1);
+
+ // 이 다음으로 갈 수 있는 모든 목적지에 대해서 경로 탐색하기
+ if (list.get(depart) == null) return path;
+ for (String dest : list.get(depart)) {
+ // 사용한 티켓을 제외한 list 만들기
+ HashMap> newlist = new HashMap<>(list);
+ ArrayList temp = new ArrayList<>(list.get(depart));
+ temp.remove(dest);
+ if (temp.size() == 0) {
+ newlist.remove(depart);
+ } else {
+ newlist.put(depart, temp);
+ }
+
+ // 새로운 목적지로 가는 path 만들기
+ temp = new ArrayList<>(path);
+ temp.add(dest);
+
+ // 그 결과!
+ temp = findPath(temp, newlist);
+ finalpath = comparePath(temp, finalpath);
+ }
+
+ return finalpath;
+ }
+
+ private ArrayList comparePath(ArrayList path1, ArrayList path2) {
+ // 더 긴 경로가 정답일 것
+ if (path1.size() < path2.size()) return path2;
+ if (path1.size() > path2.size()) return path1;
+
+ // 길이가 같다면, 알파벳 순으로 먼저 오는 것이 정답일 것
+ ArrayList answer = path1;
+ for (int i=0; i 0) answer = path2;
+ break;
+ }
+ return answer;
+ }
+}
+~~~
diff --git a/source/diane/[programmers]60059.md b/source/diane/[programmers]60059.md
new file mode 100644
index 0000000..8204e04
--- /dev/null
+++ b/source/diane/[programmers]60059.md
@@ -0,0 +1,132 @@
+# Programmers 자물쇠와 열쇠 문제
+
+- 자물쇠와 열쇠
+ - https://programmers.co.kr/learn/courses/30/lessons/60059
+
+### 문제 이해하기
+NxN 크기의 자물쇠와 MxM 크기의 열쇠가 있다.
+자물쇠의 모든 홈에 열쇠의 돌기가 들어가고, 자물쇠의 돌기와 열쇠의 돌기가 만나지 않는 경우, 그 열쇠로 자물쇠를 열 수 있다.
+이 때 열쇠는 회전하고 이동할 수 있다.
+하나의 열쇠와 하나의 자물쇠가 주어질 때, 이 열쇠로 자물쇠를 열 수 있는지 여부를 반환하라.
+M은 항상 N 이하이고, M과 N은 3 이상 20 이하인 자연수이다.
+
+#### 입력
+- int[][] key : 열쇠의 모양, 0은 홈 부분, 1은 돌기 부분.
+- int[][] lock : 자물쇠의 모양, 0은 홈 부분, 1은 돌기 부분.
+
+#### 출력
+- boolean : 주어진 열쇠로 자물쇠를 열 수 있는지 여부
+
+### 문제 접근 방법
+열쇠로 자물쇠를 열 수 있는 조건은 아래와 같다.
+1. 자물쇠의 모든 홈에 열쇠의 돌기가 있을 것
+2. 자물쇠의 돌기와 열쇠의 돌기가 만나지 않을 것
+
+자물쇠의 홈 부분이 없는 경우는 이미 자물쇠가 열린 상태이므로 true를 반환하고, 열쇠의 돌기의 수가 자물쇠의 홈의 수보다 작은 경우는 무슨 수를 써도 열쇠로 자물쇠를 열 수 없으므로 false를 반환한다.
+
+자물쇠의 홈 중에 하나를 선택하여, 열쇠의 모든 돌기를 차례대로 그 홈에 맞추어보고, 그 때 자물쇠의 모든 홈을 열쇠의 돌기로 채울 수 있는지 확인한다 (1번 조건).
+만약 이 조건을 만족한다면, 이제 열쇠의 모든 돌기에 대해서 자물쇠의 홈에 들어가지 않고 자물쇠의 돌기와 만나는 부분이 없는지 확인한다(2번 조건).
+두 조건을 모두 만족하면, 열쇠로 자물쇠를 열 수 있으므로 true를 반환하고,
+그렇지 않다면 열쇠를 90도씩 돌려가며 위의 과정을 반복하여 자물쇠를 열어본다.
+열쇠를 90도씩 돌려가며 모든 방향에 대해 확인했는데도 자물쇠를 열 수 없다면 false를 반환한다.
+
+
+### 문제를 해결한 코드
+~~~java
+import java.util.ArrayList;
+
+public class Solution {
+ private ArrayList locks;
+ private ArrayList keys;
+
+ public boolean solution(int[][] key, int[][] lock) {
+ boolean answer = true;
+
+ locks = makeList(lock, 0);
+ keys = makeList(key, 1);
+
+ if (locks.size() == 0) return true; // 이미 열려있는 경우
+ if (locks.size() > keys.size()) return false; // 답에 영향이 없네
+
+ // locks의 모든 것이 keys에 있어야 함
+ int size = keys.size();
+ for (int rotate=0; rotate<4; rotate++) {
+ for (int i = 0; i < size; i++) {
+ answer = true;
+ int xdiff = keys.get(i).x-locks.get(0).x;
+ int ydiff = keys.get(i).y-locks.get(0).y;
+ for (Pair l : locks) {
+ Pair temp = new Pair(l.x+xdiff, l.y+ydiff);
+ if (!keys.contains(temp)) {
+ answer = false;
+ break;
+ }
+ }
+ if (answer && NotExistConflict(lock.length, xdiff, ydiff)) {
+ return true;
+ }
+ }
+ keys = rotateRight(keys, key.length);
+ }
+
+ return answer;
+ }
+
+ private boolean NotExistConflict(int n, int xdiff, int ydiff) {
+ if (locks.size() == keys.size()) return true;
+ // key의 튀어나온 부분과 lock의 튀어나온 부분이 충돌하는 경우
+ for (Pair key : keys) {
+ Pair temp = new Pair(key.x-xdiff, key.y-ydiff);
+ if (!locks.contains(temp)) {
+ if (temp.x >=0 && temp.x < n && temp.y >=0 && temp.y < n)
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private ArrayList makeList(int[][] rawData, int flag) {
+ ArrayList result = new ArrayList<>();
+ int length = rawData.length;
+ for (int i=0; i rotateRight(ArrayList list, int length) {
+ ArrayList result = new ArrayList<>();
+ for (Pair pair : list) {
+ result.add(new Pair(pair.y, length-pair.x));
+ }
+ return result;
+ }
+
+}
+
+class Pair extends Object {
+ public int x;
+ public int y;
+
+ public Pair(int x, int y) {
+ this.x = x; this.y = y;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass()!=o.getClass()) return false;
+ Pair p = (Pair) o;
+ return (x==p.x)&&(y==p.y);
+ }
+
+ @Override
+ public int hashCode() {
+ return x*100+y;
+ }
+}
+~~~
+
diff --git a/source/eunbee/.DS_Store b/source/eunbee/.DS_Store
new file mode 100644
index 0000000..ba488e3
Binary files /dev/null and b/source/eunbee/.DS_Store differ
diff --git a/source/eunbee/.gitignore b/source/eunbee/.gitignore
new file mode 100644
index 0000000..e10e727
--- /dev/null
+++ b/source/eunbee/.gitignore
@@ -0,0 +1 @@
+/.metadata/
diff --git a/source/eunbee/boj/.DS_Store b/source/eunbee/boj/.DS_Store
new file mode 100644
index 0000000..4bf7b64
Binary files /dev/null and b/source/eunbee/boj/.DS_Store differ
diff --git a/source/eunbee/boj/.classpath b/source/eunbee/boj/.classpath
new file mode 100644
index 0000000..1cd9d95
--- /dev/null
+++ b/source/eunbee/boj/.classpath
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/source/eunbee/boj/.gitignore b/source/eunbee/boj/.gitignore
new file mode 100644
index 0000000..ae3c172
--- /dev/null
+++ b/source/eunbee/boj/.gitignore
@@ -0,0 +1 @@
+/bin/
diff --git a/source/eunbee/boj/.project b/source/eunbee/boj/.project
new file mode 100644
index 0000000..79a2957
--- /dev/null
+++ b/source/eunbee/boj/.project
@@ -0,0 +1,17 @@
+
+
+ boj
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/source/eunbee/boj/.settings/org.eclipse.jdt.core.prefs b/source/eunbee/boj/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..910a770
--- /dev/null
+++ b/source/eunbee/boj/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,14 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=14
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=14
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=14
diff --git a/source/eunbee/boj/src/.DS_Store b/source/eunbee/boj/src/.DS_Store
new file mode 100644
index 0000000..478d1bc
Binary files /dev/null and b/source/eunbee/boj/src/.DS_Store differ
diff --git a/source/eunbee/boj/src/boj/boj_2583.java b/source/eunbee/boj/src/boj/boj_2583.java
new file mode 100644
index 0000000..a9c1fec
--- /dev/null
+++ b/source/eunbee/boj/src/boj/boj_2583.java
@@ -0,0 +1,85 @@
+package boj;
+import java.util.*;
+
+public class boj_2583 {
+ public static int n, m, k;
+ public static int[][] graph = new int[100][100];
+ //public static int[] size = new int[100];
+ public static ArrayList size= new ArrayList();
+ public static int check = 0;
+
+ public static boolean dfs(int x, int y) {
+ if(x<0 || x >=m || y<0 || y >= n) {
+ return false;
+ }
+ if(graph[x][y] == 0) {
+ graph[x][y] = 1;
+ //상
+ dfs(x-1,y);
+ //하
+ dfs(x+1,y);
+ //좌
+ dfs(x,y-1);
+ //
+ dfs(x,y+1);
+ check++;
+ return true;
+ }
+
+ return false;
+ }
+
+ public static void main(String[] args) {
+ // TODO Auto-generated method stub
+ Scanner sc = new Scanner(System.in);
+ m = sc.nextInt();
+ n = sc.nextInt();
+ k = sc.nextInt();
+ sc.nextLine();
+
+ for(int i=0;i answerlist = new ArrayList();
+ HashMap genrePlayHashMap = new HashMap();
+
+ for(int i =0; i key = genrePlayHashMap.keySet();
+ HashMap playGenreHashMap = new HashMap();
+ for(String k : key) playGenreHashMap.put(genrePlayHashMap.get(k), k);
+
+ //플레이수 : 장르 오름차순
+ TreeMap treeMap = new TreeMap(playGenreHashMap);
+ int treeMapSize = treeMap.size();
+ for(int i =0; i8){
+ answer = -1;
+ return;
+ }
+ if(number == prev){
+ if(answer ==-1 || answer>cnt){
+ answer = cnt;
+ return;
+ }
+ }
+ for(int i=0; i<8-cnt; i++){
+ dfs(N, number, cnt+i+1, prev-nn);
+ dfs(N, number, cnt+i+1, prev+nn);
+ dfs(N, number, cnt+i+1, prev*nn);
+ dfs(N, number, cnt+i+1, prev/nn);
+ nn = nn*10+N;
+ }
+ }
+}
+```
+
diff --git a/source/woodi/201023_Programmers_43238.md b/source/woodi/201023_Programmers_43238.md
new file mode 100644
index 0000000..fecdb77
--- /dev/null
+++ b/source/woodi/201023_Programmers_43238.md
@@ -0,0 +1,46 @@
+# 프로그래머스 이분탐색문제
+- 입국심사
+ - https://programmers.co.kr/learn/courses/30/lessons/43238
+
+## 풀이 방법
+### 문제 이해하기
+- 입국심사를 기다리는 사람 수 n
+- int[] times : 각 심사관이 한 명을 심사하는데 걸리는 시간이 담긴 배열
+- 가장 앞에 서 있는 사람은 비어 있는 심사대로 가서 심사를 받을 수 있습니다. 하지만 더 빨리 끝나는 심사대가 있으면 기다렸다가 그곳으로 가서 심사를 받을 수도 있습니다.
+- 모든 사람이 심사를 받는데 걸리는 최소 시간을 구하시오.
+
+
+### 문제 접근 방법
+- 정답을 가정(mid)하고 조건(n)과 비교한다. -> 가장 n과 유사한 mid가 정답
+- mid 시간 이내에 심사 가능한 인원의 수 -> sum(mid/times[i])=result, n과 result 비교, n== result이면 mid 값을 반환한다.
+### 구현 배경 지식
+- 이분탐색
+### 접근 방법을 적용한 코드
+```java
+import java.util.*;
+
+class Solution {
+ public long solution(int n, int[] times) {
+ long answer = 0;
+ Arrays.sort(times);
+ long left =1;
+ long right = (long)n*times[times.length-1]; // 가장 오래 걸리는 경우
+ while(left<=right){
+ long mid = (left+right)/2;
+ long sum=0; // mid 시간 이내에 심사 가능한 인원의 수
+ for(int t : times){
+ sum+= (mid/t);
+ }
+ if(sum 이후 d[lastidx] 중 가장 큰 값이 answer이다
+
+ for(int i=0; i li = new ArrayList<>();
+ for(int i=0; i q = new LinkedList<>();
+ q.add(begin);// begin을 담는다.
+ d[d.length-1] = 0;
+// System.out.println("begin: "+begin);
+ while(!q.isEmpty()){
+ String now = q.remove();
+// System.out.println("now: "+now);
+ if(now.equals(target)) {
+ answer = d[li.indexOf(now)];
+ break;
+ }
+ for(int i=0; imap[a+1][i]) {// 경사로 : \
+ boolean slopePossible=true;
+ for(int t=a+2; ta-l; t--) {
+ if(t<0 || map[a][i]!=map[t][i]) {
+ slopePossible = false;
+ }
+ }
+ if(!slopePossible) {
+ result = false;
+ break;
+ }else {
+ a++;
+ }
+ }
+ }else if(Math.abs(map[a][i]-map[a+1][i])==0){
+ a++;
+ }else {
+ result = false;
+ break;
+ }
+ }
+ return result;
+ }
+ public static boolean checkRow(int i) { // map[i][0~n-1]
+ boolean result= true;
+ int a=0;
+ while(amap[i][a+1]) {// 경사로 : \
+ boolean slopePossible=true;
+ for(int t=a+2; ta-l; t--) {
+ if(t<0 ||map[i][a]!=map[i][t]) {
+ slopePossible = false;
+ }
+ }
+ if(!slopePossible) {
+ result = false;
+ break;
+ }else {
+ a++;
+ }
+ }
+ }else if(Math.abs(map[a][i]-map[a+1][i])==0){
+ a++;
+ }else {
+ result = false;
+ break;
+ }
+ }
+ return result;
+ }
+ public static void main(String[] args) throws IOException {
+ BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+ StringTokenizer st = new StringTokenizer(br.readLine());
+ n = Integer.parseInt(st.nextToken());
+ l = Integer.parseInt(st.nextToken());
+ map = new int[n][n];
+ for(int i=0; i
+- 첫째 줄) N: 격자 크기, M: 상어 마리 수 , K: 냄새가 사라지는데 걸리는 시간
+- 둘째 줄~N개의 줄 ) 0은 빈칸, 그 외 0이 아닌 수 x는 x번 상어가 들어가 있는 칸
+- 그 다음 줄 ) 각 상어의 방향 (1: 위, 2: 아래, 3: 좌, 4: 우)
+- 그 다음 줄~) 각 상어의 방향 우선 순위 (하나의 상어당 4줄(현재 방향), 각 줄은 4개로 이루어짐(현재 방향에 따른 우선순위))
+- <출력>
+- 1번 상어만 격자에 남게 되기까지 걸리는 시간 출력. 단, 1000초를 넘어갈 경우 -1 출력
+
+### 문제 접근 방법
+-
+### 구현 배경 지식
+- 시뮬레이션
+### 접근 방법을 적용한 코드
+```java
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.StringTokenizer;
+public class AdultShark {
+
+ static int[][][] priority; // 상어별 이동 우선순위 : 1(위), 2(아래), 3(좌), 4(우)
+ // priority[1] : 상어 1
+ // priority[1][2] : 상어1의 현재 방향 (아래)
+ // priority[1][2][1] : 상어1의 현재 방향에서 첫번째 우선순위
+ static int n;
+ static int m;
+ static int k;
+ static int[] di = {0, -1, 1, 0, 0};
+ static int[] dj = {0, 0, 0, -1, 1};
+
+ public static boolean checkBound(int x, int y) {
+ if(x<0 || x>=n || y<0 || y>=n) {
+ return false;
+ }
+ return true;
+ }
+
+ public static void move(int[][] map_smell, int[][] map_shark, int[] curr_direct, int[][] map_smell_own, int count_shark) {
+ int time = 0;
+ // count_shark
+ while(true) {
+
+ // 1초 후
+ time++;
+ // map_smell의 모든 숫자는 1씩 감소하고
+// for(int i=0; i0)
+// map_smell[i][j]--;
+// }
+// }
+// System.out.println("---------------------");
+// System.out.println(time);
+// printMap(map_shark);
+// System.out.println();
+// printSmell(map_smell);
+ // 모든 상어가 각자의 우선순위에 따라 움직임
+ for(int i=0; i update curr_direct[shark_num]
+ if(checkBound(tempi, tempj) && map_smell[tempi][tempj]==0) {
+ curr_direct[shark_num] = next_direct;
+ flag = true;
+ break;
+ }else { // 그렇지 않으면 다음 p
+ continue;
+ }
+ }
+ // p를 다 돌았는데도 아무 냄새 없는 칸이 없어(flag==false) -> 자신의 냄새가 있는 칸으로 update curr_direct[shark_num]
+
+ if(flag==false) {
+// System.out.println("냄새 없는 칸이 없음. 자신의 냄새가 있는 곳 탐색");
+ for(int p=1; p<=4; p++) {
+ int next_direct = priority[shark_num][curr_direct[shark_num]][p];
+ int tempi = i+di[next_direct];
+ int tempj = j+dj[next_direct];
+ // tempi, tempj가 격자 밖으로 나가는지 검사하기
+ // next_move 한 칸에 자신의 냄새가 있으면 -> update curr_direct[shark_num]
+ if(checkBound(tempi, tempj) && map_smell_own[tempi][tempj]==shark_num) {
+ curr_direct[shark_num] = next_direct;
+ flag = true;
+ break;
+ }else { // 그렇지 않으면 다음 p
+ continue;
+ }
+ }
+ }
+ }
+ }
+ }
+ // curr_direct에 따라 상어의 새로운 위치를 구하고
+
+ int[][] new_shark_map = new int[n][n];
+
+ for(int i=0; i 더 작은 숫자의 상어가 차지 한다.
+ int a = new_shark_map[ni][nj];
+ if(shark0)
+ map_smell[i][j]--;
+ }
+ }
+ // 새로운 위치 중 겹치는 위치가 있으면 가장 숫자가 작은 상어가 차지한다. --> update map_shark
+ // (이때 사라지는 상어 수 만큼 count_shark-- 해준다.)
+ // 냄새를 뿌린다. --> update map_smell, map_smell_own
+ for(int i=0; i=1000) {
+ System.out.println(-1);
+ break;
+ }
+// System.out.println(count_shark);
+ }
+ // while 문 끝남 -> 1번 샤크만 남았을 것
+ }
+ public static int[][] copyMap(int[][] new_map_shark){
+ int[][] map = new int[n][n];
+ for(int i=0; i[] link에 담는다.
+- link[i]에는 i번 컴퓨터와 연결된 다른 컴퓨터들의 번호가 ArrayList로 담긴다.
+- BFS로 탐색한다.
+### 구현 배경 지식
+- BFS
+### 접근 방법을 적용한 코드
+```java
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+class Solution {
+ public int solution(int n, int[][] computers) {
+ int answer = 0; // network 개수
+ ArrayList[] link = new ArrayList[n]; // 안해주면 object 형태로 저장 (generic)
+ for(int i=0; i();
+ }
+ // 1. 연결된 컴퓨터 정보 담기
+ for(int i=0; i q = new LinkedList<>();
+ while(count!=n) {
+ System.out.println("count :"+count);
+ // 아직 방문 안한 노드 중 하나를 추가한다.
+ for(int i=0; i
+- 첫째 줄) N: 격자 크기, M: 상어 마리 수 , K: 냄새가 사라지는데 걸리는 시간
+- 둘째 줄~N개의 줄 ) 0은 빈칸, 그 외 0이 아닌 수 x는 x번 상어가 들어가 있는 칸
+- 그 다음 줄 ) 각 상어의 방향 (1: 위, 2: 아래, 3: 좌, 4: 우)
+- 그 다음 줄~) 각 상어의 방향 우선 순위 (하나의 상어당 4줄(현재 방향), 각 줄은 4개로 이루어짐(현재 방향에 따른 우선순위))
+- <출력>
+- 1번 상어만 격자에 남게 되기까지 걸리는 시간 출력. 단, 1000초를 넘어갈 경우 -1 출력
+
+### 문제 접근 방법
+-
+### 구현 배경 지식
+- 시뮬레이션
+### 접근 방법을 적용한 코드
+```java
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.StringTokenizer;
+public class AdultShark {
+
+ static int[][][] priority; // 상어별 이동 우선순위 : 1(위), 2(아래), 3(좌), 4(우)
+ // priority[1] : 상어 1
+ // priority[1][2] : 상어1의 현재 방향 (아래)
+ // priority[1][2][1] : 상어1의 현재 방향에서 첫번째 우선순위
+ static int n;
+ static int m;
+ static int k;
+ static int[] di = {0, -1, 1, 0, 0};
+ static int[] dj = {0, 0, 0, -1, 1};
+
+ public static boolean checkBound(int x, int y) {
+ if(x<0 || x>=n || y<0 || y>=n) {
+ return false;
+ }
+ return true;
+ }
+
+ public static void move(int[][] map_smell, int[][] map_shark, int[] curr_direct, int[][] map_smell_own, int count_shark) {
+ int time = 0;
+ // count_shark
+ while(true) {
+
+ // 1초 후
+ time++;
+ // map_smell의 모든 숫자는 1씩 감소하고
+// for(int i=0; i0)
+// map_smell[i][j]--;
+// }
+// }
+// System.out.println("---------------------");
+// System.out.println(time);
+// printMap(map_shark);
+// System.out.println();
+// printSmell(map_smell);
+ // 모든 상어가 각자의 우선순위에 따라 움직임
+ for(int i=0; i update curr_direct[shark_num]
+ if(checkBound(tempi, tempj) && map_smell[tempi][tempj]==0) {
+ curr_direct[shark_num] = next_direct;
+ flag = true;
+ break;
+ }else { // 그렇지 않으면 다음 p
+ continue;
+ }
+ }
+ // p를 다 돌았는데도 아무 냄새 없는 칸이 없어(flag==false) -> 자신의 냄새가 있는 칸으로 update curr_direct[shark_num]
+
+ if(flag==false) {
+// System.out.println("냄새 없는 칸이 없음. 자신의 냄새가 있는 곳 탐색");
+ for(int p=1; p<=4; p++) {
+ int next_direct = priority[shark_num][curr_direct[shark_num]][p];
+ int tempi = i+di[next_direct];
+ int tempj = j+dj[next_direct];
+ // tempi, tempj가 격자 밖으로 나가는지 검사하기
+ // next_move 한 칸에 자신의 냄새가 있으면 -> update curr_direct[shark_num]
+ if(checkBound(tempi, tempj) && map_smell_own[tempi][tempj]==shark_num) {
+ curr_direct[shark_num] = next_direct;
+ flag = true;
+ break;
+ }else { // 그렇지 않으면 다음 p
+ continue;
+ }
+ }
+ }
+ }
+ }
+ }
+ // curr_direct에 따라 상어의 새로운 위치를 구하고
+
+ int[][] new_shark_map = new int[n][n];
+
+ for(int i=0; i 더 작은 숫자의 상어가 차지 한다.
+ int a = new_shark_map[ni][nj];
+ if(shark0)
+ map_smell[i][j]--;
+ }
+ }
+ // 새로운 위치 중 겹치는 위치가 있으면 가장 숫자가 작은 상어가 차지한다. --> update map_shark
+ // (이때 사라지는 상어 수 만큼 count_shark-- 해준다.)
+ // 냄새를 뿌린다. --> update map_smell, map_smell_own
+ for(int i=0; i=1000) {
+ System.out.println(-1);
+ break;
+ }
+// System.out.println(count_shark);
+ }
+ // while 문 끝남 -> 1번 샤크만 남았을 것
+ }
+ public static int[][] copyMap(int[][] new_map_shark){
+ int[][] map = new int[n][n];
+ for(int i=0; i=5) {
+ d[5]=1;
+ }
+
+ for(int i=6; i<=n; i++) {
+ if(d[i-5]>0) {
+ d[i]=d[i-5]+1;
+ }else if(d[i-3]>0) {
+ d[i]=d[i-3]+1;
+ }
+ }
+
+ int answer;
+ if(d[n]==0) {
+ answer =-1;
+ }else {
+ answer = d[n];
+ }
+ System.out.println(answer);
+ }
+}
+
+```
+
diff --git a/source/woodi/201226_programmers_43164.md b/source/woodi/201226_programmers_43164.md
new file mode 100644
index 0000000..54078d6
--- /dev/null
+++ b/source/woodi/201226_programmers_43164.md
@@ -0,0 +1,111 @@
+# 프로그래머스 dfs
+- 여행경로
+ - https://programmers.co.kr/learn/courses/30/lessons/43164
+
+## 풀이 방법
+### 문제 이해하기
+- 주어진 항공권을 '모두' 이용하여 여행경로를 짤때, 이 경로를 출력해라
+- 항상 "ICN" 공항에서 출발한다.
+- [입력]
+ - 항공권 정보가 담긴 2차원 배열 tickets
+- [출력]
+ - 방문하는 공항 경로를 1차원 배열에 담아 출력
+- [추가 조건]
+ - 모든 공항은 알파벳 대문자 3글자
+ - 주어진 공항 수는 3개 이상 10,000개 이하
+ - tickets의 각 행 [a,b]는 a공항에서 b공항으로 가는 항공권이 있다는 뜻
+ - 주어진 항공권은 모두 사용해야함
+ - 가능한 경로가 2개 이상일 경우, 알파벳 순서가 앞서는 경로를 return
+ - 모든 도시를 방문할 수 없는 경우는 주어지지 않음
+
+### 문제 접근 방법
+-
+### 구현 배경 지식
+- DFS
+### 접근 방법을 적용한 코드
+```java
+package programmers;
+
+import java.util.*;
+
+public class bfsdfs_43164 {
+ static ArrayList candidates;
+ public static void dfs(String depart, HashMap> map,String[] path, int i) {
+ // 출발지, 출발지에서 직통으로 갈수있는 도시 map, 현재까지 경로, 현재까지 경로 인덱스
+
+ // 더 이상 갈 수 있는 경로(도시)가 없는 경우
+ if(map.get(depart)==null || map.get(depart).size()==0) {
+ // 마지막 도시까지 전부 방문. 즉, path를 다 채움
+ if(i==path.length-1) {
+ String[] newpath = new String[path.length]; // 경로를 값만 복사 (깊은 복사)
+ // 복사를 안하고 candidates에 담으면 추후 path가 바뀔때마다 저장된 값도 바뀜(주소값이 저장되므로)
+ for(int t=0; t li = map.get(depart);
+ i++;
+
+ // for문 돌면서 remove하기 위해 임시로 복사해둠
+ ArrayList templi = new ArrayList<>();
+ templi.addAll(li);
+
+ for(String next:templi) {
+ // 해당 ticket을 사용했을 경우, li에서 지워버린 후 map에 저장 -> dfs
+ li.remove(next);
+ map.put(depart, li);
+ path[i] = next;
+ dfs(next,map,path,i);
+ // 백트래킹
+ li.add(next);
+ map.put(depart, li);
+ }
+ }
+ public static String[] solution(String[][] tickets) {
+ String[] answer = {};
+ HashMap> map = new HashMap<>();
+ // key: 출발지, value : 출발지에서 직통으로 갈 수 있는 도시들
+ candidates = new ArrayList<>();
+ for(int i=0; i());
+ map.get(tickets[i][0]).add(tickets[i][1]);
+ }
+ }
+
+ String[] path = new String[tickets.length+1]; // 경로
+ path[0] = "ICN";
+ dfs("ICN", map, path,0); // 가능한 경로를 모두 candidates에 담는다.
+
+ // 알파벳 순으로 정렬
+ Collections.sort(candidates, new Comparator(){
+ @Override
+ public int compare(String[] o1, String[] o2) {
+ return Arrays.toString(o1).compareTo(Arrays.toString(o2));
+ }
+ });
+ // 가장 앞에 있는 것이 답이다.
+ answer = candidates.get(0);
+ return answer;
+ }
+
+ public static void main(String[] args) {
+ String[][] tickets1 = {{"ICN", "JFK"}, {"HND", "IAD"}, {"JFK", "HND"}};
+ String[][] tickets2 = {{"ICN", "SFO"}, {"ICN", "ATL"}, {"SFO", "ATL"}, {"ATL", "ICN"}, {"ATL","SFO"}};
+ String[][] tickets3 = {{"ICN", "A"}, {"ICN", "B"}, {"B", "ICN"}};
+ String[] answer = solution(tickets3);
+ System.out.println("정답 : "+Arrays.toString(answer));
+ }
+}
+
+
+```
+
diff --git a/source/woodi/210116_boj_2887.md b/source/woodi/210116_boj_2887.md
new file mode 100644
index 0000000..124fbfc
--- /dev/null
+++ b/source/woodi/210116_boj_2887.md
@@ -0,0 +1,144 @@
+# 백준 MST
+- 행성터널
+ - https://www.acmicpc.net/problem/2887
+
+## 풀이 방법
+### 문제 이해하기
+- 각 행성의 좌표(x,y,z)가 주어질 때
+- 두 행성 A(xA, yA, zA)와 B(xB, yB, zB)를 터널로 연결할 때 드는 비용은 min(|xA-xB|, |yA-yB|, |zA-zB|)이다
+- 터널을 총 N-1개 건설해서 모든 행성이 서로 연결되게 하려고 한다. 이때, 모든 행성을 터널로 연결하는데 필요한 최소 비용을 구하시오
+
+### 문제 접근 방법
+- 두 행성을 연결하는 간선이 3개(x,y,z 기준)씩 있다고 생각한다.
+- 모든 행성들을 node list에 담고 x, y, z 각각에 대해서 정렬한 후,
+- 각 행성의 번호화 비용을 edgeList에 추가한다.
+- 그 결과 각 행성간의 x,y,z 거리(에지)가 edgeList에 저장된다.
+- edgeList를 오름차순으로 정렬 후, 크루스칼 MST를 적용한다.
+### 구현 배경 지식
+- MST : 크루스칼
+### 접근 방법을 적용한 코드
+```java
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.StringTokenizer;
+
+// https://www.acmicpc.net/problem/2887
+class Node{
+ int num;
+ int x;
+ int y;
+ int z;
+ public Node(int num, int x, int y, int z){
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.num = num;
+ }
+}
+class Edge implements Comparable{
+ int start;
+ int end;
+ int weight;
+
+ Edge(int start, int end, int weight){
+ this.start = start;
+ this.end = end;
+ this.weight = weight;
+ }
+ @Override
+ public int compareTo(Edge o) {
+ // TODO Auto-generated method stub
+ return weight -o.weight;
+ }
+
+}
+
+public class boj_2887 {
+ static int[] parent;
+ static ArrayList edgeList;
+
+ public static void main(String[] args) throws IOException {
+ BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+ StringTokenizer st =null;
+ int n = Integer.parseInt(br.readLine()); // 행성의 개수
+
+ Node[] nodes = new Node[n];
+ for(int i=0; i();
+
+ // x, y, z 각각에 대해서 정렬하고 각 행성의 번호화 비용을 edgeList에 추가
+ Arrays.sort(nodes, (n1,n2)->n1.x-n2.x);
+ for(int i=0; in1.y-n2.y);
+ for(int i=0; in1.z-n2.z);
+ for(int i=0; i=N || y>=M) {
+ return true;
+ }
+ return false;
+ }
+ public static void main(String[] args) throws IOException {
+ BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+ StringTokenizer st = new StringTokenizer(br.readLine());
+ M = Integer.parseInt(st.nextToken()); // y
+ N = Integer.parseInt(st.nextToken()); // x
+ K = Integer.parseInt(st.nextToken());
+ List li = new ArrayList<>();
+ Block[][] blockli = new Block[N][M];
+ // 색칠한 영역 추가
+ int lx=0,ly=0,rx=0,ry=0;
+ for(int i=0; i hm = new HashMap<>(); //
+ ArrayList ar = new ArrayList<>();
+ int count=0;
+ // bfs 탐색 시작
+ Queue q = new LinkedList();
+ for(Block b : li) {
+ if(b.check) {
+// System.out.println(b.x+", "+b.y);
+ continue;
+ }
+ q.add(b);
+ blockli[b.x][b.y].check=true;
+ int square=0; // 넓이
+ while(!q.isEmpty()) {
+ Block now = q.remove();
+ int x = now.x;
+ int y = now.y;
+ square++;
+ for(int i=0; i<4; i++) {
+ int nx = x+dx[i];
+ int ny = y+dy[i];
+ if(!isOutOfBound(nx, ny) && !blockli[nx][ny].check ) {
+ blockli[nx][ny].check=true;
+ q.add(blockli[nx][ny]);
+// square++;
+ }
+ }
+ }
+// debug(blockli);
+ count++;
+ ar.add(square);
+ }
+
+ System.out.println(count);
+ Collections.sort(ar);
+ for(int a : ar) {
+ System.out.print(a+" ");
+ }
+ }
+}
+
+```
+
diff --git a/source/woodi/210320_boj_1931.md b/source/woodi/210320_boj_1931.md
new file mode 100644
index 0000000..af57066
--- /dev/null
+++ b/source/woodi/210320_boj_1931.md
@@ -0,0 +1,105 @@
+# 백준 MST
+- 회의실 배정
+ - https://www.acmicpc.net/problem/1931
+
+## 풀이 방법
+### 문제 이해하기
+- 하나의 회의실이 있음
+- N개의 회의에 대하여 회의실 사용표를 만들려고한다.
+- 각 회의에 대해서는 시작시간과 끝나느 시간이 주어짐
+- 이때 각 회의가 겹치지 않게 하면서 회의실을 사용할 수 있는 회의의 최대 개수를 찾아라
+- (단, 회의의 시작 시간과 끝나는 시간이 같을 수도 있다.)
+
+### 문제 접근 방법
+
+1. 목록 S에 남은 회의실 중 가장 일찍 끝나는 회의 Smin을 선택한다.
+2. Smin과 겹치는 회의를 S에서 모두 지운다
+3. S가 텅 빌 때까지 반복한다.
+
+- 조건 '가장 종료 시간이 빠른 회의(Smin)를 포함하는 최적해가 반드시 존재한다.'가 성립.
+
+- 증명)
+ - S의 최적해 중 Smin을 포함하지 않는 답 (S')가 존재
+ - 이 답(S')은 서로 겹치지 않는 회의의 목록임
+ - S'에서 첫번째로 개최되는 회의를 지우고, Smin을 대신 추가해서 새로운 목록을 만든다.
+ - 이때, Smin은 S에서 가장 일찍 끝나는 회의이기 때문에 지워진 회의는 Smin보다 일찍 끝날 수 없다.
+ - 따라서 S'의 가장 첫번째 회의를 Smin으로 대체하여 새로 만든 목록 역시 최적해 중 하나이다.
+
+- 정리)
+ - S' = {a,b,c,d, ....} (a,b,c,d..는 서로 겹치지 않음)
+ - Smin의 끝나는 시간 < a의 끝나는시간
+ - S'' = {Smin, b,c,d, ...} -> 마찬가지로 최적해
+
+
+
+### 구현 배경 지식
+- Greedy
+### 접근 방법을 적용한 코드
+```java
+import java.util.ArrayList;
+import java.util.PriorityQueue;
+import java.util.Scanner;
+
+public class boj_1931 {
+ static class Node implements Comparable{
+
+ int s;
+ int e;
+
+ public Node(int s, int e) {
+ this.s = s;
+ this.e = e;
+ }
+
+ // 빨리 끝나는 순으로 정렬
+ @Override
+ public int compareTo(Node o) {
+ if(this.e == o.e) {
+ return Integer.compare(this.s, o.s);
+ }
+ return Integer.compare(this.e, o.e);
+ }
+ }
+
+ public static void main(String[] args) {
+ Scanner sc = new Scanner(System.in);
+ int n = sc.nextInt();
+ PriorityQueue pq = new PriorityQueue();
+ for(int i=0; i pq.peek().s)) {
+ pq.remove();
+ }
+ }
+
+ System.out.println("result : "+ cnt);
+ }
+}
+
+
+```
+
+
+### 그리디 알고리즘
+#### 완전 탐색(혹은 DP)과 그리디
+1. 공통점 : (분할정복) 여러 조각으로 쪼개고, 각 단계마다 답의 한 부분을 만들어감
+2. 차이점
+ - 완탐 : 모든 선택지를 고려해보고 그 중 전체 답이 가장 좋은 방법을 선택
+ - 그리디 : 각 단계마다 '지금 당장' 좋은 방법만을 선택 (지금 선택이 나중에 어떤 영향을 미칠지 고려하지 않는다.)
+
+- 참고)
+ - 탐욕법으로 최적해를 찾을 수 있는 많은 문제들은 동적 계획법으로도 풀 수 있다.
+ - 탐욕법으로 최적해를 찾을 수 있다 = 지금 한 단계만을 고려해도 답을 찾을 수 있다.
+ - 따라서 동적 계획법은 모든 단계를 고려하므로 답이 틀릴 수가 없다.
+ - 그럼에도 그리디를 사용하는 이유는 동적 계획법에 필요한 메모리나 시간이 과도하게 크기 때문이다.
\ No newline at end of file
diff --git a/source/woodi/210327_programmers_42862.md b/source/woodi/210327_programmers_42862.md
new file mode 100644
index 0000000..f4e5e74
--- /dev/null
+++ b/source/woodi/210327_programmers_42862.md
@@ -0,0 +1,88 @@
+# 프로그래머스
+- 체육복
+ - https://programmers.co.kr/learn/courses/30/lessons/42862?language=java
+
+## 풀이 방법
+### 문제 이해하기
+- <입력>
+- 전체 학생 수 n (2 <= n <= 30)
+- 도난 학생 배열 lost (1 <= lost.length <= n)
+- 여벌 학생 배열 reserve
+
+- <조건>
+- 여벌 옷이 있는 학생 번호 +1, -1 한테만 빌려줄 수 있음
+- 여벌 옷이 있는 학생도 도난 가능, 이 경우 하나만 도난 당한다고 가정. 빌려 줄 수 없다.
+
+- 이때 체육 수업을 들을 수 있는 최대 학생 수를 구하라
+
+### 문제 접근 방법
+- 전체 학생 배열 int[] student에 대하여 여벌 있으면 1, 도난 -1, 둘다 아니면 0, 여벌이 있으나 도난 당하면 0으로 초기화
+- student 배열을 for 문으로 돌면서
+ - student[i] == -1 이면,
+ - 빌려 줄 수 있는 경우가 1개
+ - student[i+1], student[i-1] 둘 중 하나 값이 1일 경우 -> answer++, student[i+1] or student[i-1] =0으로 set
+ - i가 1이거나 n인 경우
+ - 빌려 줄 수 있는 경우가 2개 (student[i+1]==1 && student[i-1]==1)
+ - 앞에껄 빌려준다. 즉, student[i-1]을 먼저 빌려준다. (그리디)
+ - 뒤에꺼부터 빌려주면 나중에 도난 당한 사람이 못 빌릴 수도 있음
+ - 아니면, answer++
+### 구현 배경 지식
+- 그리디
+### 접근 방법을 적용한 코드
+```java
+class Solution {
+ public int solution(int n, int[] lost, int[] reserve) {
+ int answer = 0;
+
+ int[] student = new int[n+1]; // 잃어버림 = -1, 여벌 = 1, 여벌있는데 잃어버림 =0, 둘다 아님 =0
+
+ for(int i=0; i lock의 홈 딱 맞으면 열림
+ - 돌기와 돌기가 만나면 안됨
+ - key는 lock 영역을 벗어날 수 있음
+ - key는 회전, 이동 가능
+
+### 문제 접근 방법
+- 90도씩 회전한 4가지 형태의 keys list 만들기
+- key가 lock 영역을 벗어나는 것 까지 포함하는 전체 영역 map 만든다
+- key를 90도씩 회전하며 모든 map 영역을 탐색한다.
+### 구현 배경 지식
+- 완전탐색
+### 접근 방법을 적용한 코드
+```java
+import java.util.*;
+class Solution {
+ static int m;
+ static int n;
+ static int size;
+ public boolean solution(int[][] key, int[][] lock) {
+
+ m = key.length;
+ n = lock.length;
+ // 회전한 모든 key의 경우의 수 담기 (총 4가지)
+ int[][][] keys = lotatedKeys(key);
+
+ // map 영역 정의
+ size = n+2*m-2;
+ int[][] map = new int[size][size];
+ for(int i=m-1; i test 함수 (lock 영역의 모든 값이 1이면 true 리턴)
+ for(int t=0; t<4; t++) {
+ for(int i=0; i