├── seoul_21_jongilchoi └── mincodding │ ├── bfs │ └── 13 │ │ ├── README.md │ │ └── bfs_top_13.cpp │ └── dat_12 │ ├── README.md │ └── dat_12.cpp ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── 목표-계획.md │ └── 도움-요청.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── Auto-Author-Assign.yml ├── seoul_21_minjaekim ├── BoJ │ ├── Gold I │ │ ├── boj2014 │ │ │ ├── README.md │ │ │ └── boj2014.cpp │ │ └── boj2098 │ │ │ ├── boj2098.cpp │ │ │ └── README.md │ ├── Silver II │ │ └── boj1260 │ │ │ ├── boj1260.py │ │ │ └── README.md │ ├── Gold IV │ │ └── boj2602 │ │ │ ├── boj2602.cpp │ │ │ └── README.md │ └── Platinum IV │ │ └── boj13907 │ │ ├── boj13907.cpp │ │ └── README.md ├── MinCoding │ └── Algorithm Tower │ │ ├── Backtracking Tower │ │ ├── 8 │ │ │ ├── min_backtracking_tower_8.cpp │ │ │ └── README.md │ │ └── 9 │ │ │ ├── min_backtracking_tower_9.cpp │ │ │ └── README.md │ │ ├── DAT Tower │ │ └── 12 │ │ │ ├── min_dat_tower_12.cpp │ │ │ └── README.md │ │ ├── Dijkstra Tower │ │ └── 6 │ │ │ ├── min_dijkstra_tower_6.cpp │ │ │ └── README.md │ │ └── Implement Tower │ │ └── 5 │ │ ├── README.md │ │ └── min_implement_tower_5.cpp ├── Softeer │ └── HSAT_7th │ │ ├── 1 │ │ ├── HSAT_7th_1.cpp │ │ └── README.md │ │ └── 2 │ │ ├── HSAT_7th_2.cpp │ │ └── README.md └── SWEA │ └── D2 │ ├── swea1204 │ ├── swea1204.cpp │ └── README.md │ ├── swea1961 │ ├── README.md │ └── swea1961.cpp │ ├── swea1959 │ ├── swea1959.cpp │ └── README.md │ ├── swea1974 │ ├── swea1974.cpp │ └── README.md │ └── swea12712 │ ├── README.md │ └── swea12712.cpp ├── seoul_11_hongyungi └── BoJ │ ├── Gold II │ └── Boj 1167 │ │ ├── ExampleTree.png │ │ ├── Boj1167.java │ │ └── README.md │ ├── Silver II │ ├── BoJ 6884 │ │ ├── README.md │ │ └── Baekjoon_6884.java │ └── BoJ 1138 │ │ ├── Baekjoon_1138.java │ │ └── README.md │ ├── Silver I │ ├── BoJ 9465 │ │ ├── Baekjoon_9465.java │ │ └── README.md │ ├── BoJ 13335 │ │ ├── README.md │ │ └── Baekjoon_13335.java │ └── BoJ 1986 │ │ ├── README.md │ │ └── Baekjoon_1986.java │ ├── Platinum V │ └── Boj 3015 │ │ ├── Baekjoon_3015.java │ │ └── README.md │ ├── Silver III │ └── boj11140 │ │ ├── README.md │ │ └── Baekjoon_11140.java │ ├── Gold V │ └── Boj 15591 │ │ ├── Boj15591.java │ │ └── README.md │ └── Gold III │ └── Boj 2206 │ ├── Boj2206.java │ └── README.md ├── seoul_x_hwijoonchoi └── BOJ │ ├── boj7490 │ ├── boj7490.py │ └── README.md │ ├── boj20529 │ ├── boj20529.py │ └── README.md │ ├── boj1431 │ ├── boj1431.py │ └── README.md │ ├── boj2194 │ ├── boj2194.py │ └── README.md │ └── boj16985 │ ├── boj16985.py │ └── README.md ├── seoul_18_kimjeonguk └── BOJ │ └── SILVER III │ └── 11478 - 서로 다른 부분 문자열의 개수 │ ├── Q11478.java │ └── readme.md ├── seoul_17_choijunho ├── SWEA │ └── swea7465.py └── BOJ │ └── boj14426.cpp ├── LICENSE ├── seoul_09_kyoohyunkim └── BOJ │ ├── Gold III │ └── boj 10986 │ │ ├── Boj_10986.java │ │ └── README.md │ ├── Silver II │ └── Boj 21736 │ │ ├── Baekjoon_21736.java │ │ └── README.md │ └── Gold I │ └── boj 17114 │ ├── Boj_17114.java │ └── README.md ├── gumi_4_wonjulee └── boj │ ├── boj1244 │ ├── boj1244.java │ └── README.md │ └── boj2493 │ ├── boj2493.java │ └── README.md ├── seoul_15_suminkim └── SWEA │ └── Solution_d5_1248.java ├── seoul_10_parkhoje └── boj15683 │ ├── boj15683.java │ └── README.md └── README.md /seoul_21_jongilchoi/mincodding/bfs/13/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @SSAFY-10th/code-reviewers 2 | -------------------------------------------------------------------------------- /seoul_21_minjaekim/BoJ/Gold I/boj2014/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SSAFY-10th/algorithm/HEAD/seoul_21_minjaekim/BoJ/Gold I/boj2014/README.md -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Gold II/Boj 1167/ExampleTree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SSAFY-10th/algorithm/HEAD/seoul_11_hongyungi/BoJ/Gold II/Boj 1167/ExampleTree.png -------------------------------------------------------------------------------- /seoul_21_minjaekim/MinCoding/Algorithm Tower/Backtracking Tower/8/min_backtracking_tower_8.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SSAFY-10th/algorithm/HEAD/seoul_21_minjaekim/MinCoding/Algorithm Tower/Backtracking Tower/8/min_backtracking_tower_8.cpp -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/목표-계획.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 목표 계획 3 | about: 목표 계획 템플릿 4 | title: "[목표 계획] " 5 | labels: 목표 계획 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## 📅 Period 11 | 12 | 13 | 14 | ## 📝 Todo 15 | 16 | - [ ] todo 17 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## 📣 Related Issue 2 | 3 | close # 4 | 5 | 6 | ## 🌁 Background 7 | 8 | 9 | 10 | ## 👩‍💻 Contents 11 | 12 | 13 | 14 | ## 📱 Screenshot 15 | 16 | 17 | 18 | ## 📝 Review Note 19 | 20 | 21 | 22 | ## 📬 Reference 23 | 24 | -------------------------------------------------------------------------------- /.github/workflows/Auto-Author-Assign.yml: -------------------------------------------------------------------------------- 1 | # .github/workflows/auto-author-assign.yml 2 | name: Auto Author Assign 3 | 4 | on: 5 | issues: 6 | types: [ opened, reopened ] 7 | pull_request: 8 | types: [ opened, reopened ] 9 | 10 | permissions: 11 | issues: write 12 | pull-requests: write 13 | 14 | jobs: 15 | assign-author: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: toshimaru/auto-author-assign@v1.6.2 19 | -------------------------------------------------------------------------------- /seoul_x_hwijoonchoi/BOJ/boj7490/boj7490.py: -------------------------------------------------------------------------------- 1 | # 2. 0만드는 백트래킹 함수 구현 2 | def make_zero(depth,seq): 3 | if depth == n: 4 | sequence = seq.replace(' ','') 5 | if eval(sequence) == 0: 6 | print(seq) 7 | return 8 | 9 | make_zero(depth+1,seq+' '+str(depth+1)) 10 | make_zero(depth+1,seq+'+'+str(depth+1)) 11 | make_zero(depth+1,seq+'-'+str(depth+1)) 12 | 13 | # 1. 입력받기 14 | t = int(input()) # test case 15 | 16 | for _ in range(t): 17 | n = int(input()) 18 | make_zero(1,'1') 19 | print('') -------------------------------------------------------------------------------- /seoul_18_kimjeonguk/BOJ/SILVER III/11478 - 서로 다른 부분 문자열의 개수/Q11478.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | import java.util.HashSet; 3 | import java.util.Set; 4 | 5 | public class Q11478 { 6 | private static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 7 | 8 | public static void main(String[] args) throws IOException { 9 | String s = br.readLine(); 10 | 11 | Set set = new HashSet<>(); 12 | 13 | for (int i = 0; i < s.length(); i++) { 14 | for (int j = i + 1; j <= s.length(); j++) { 15 | set.add(s.substring(i, j)); 16 | } 17 | } 18 | 19 | System.out.println(set.size()); 20 | } 21 | } -------------------------------------------------------------------------------- /seoul_17_choijunho/SWEA/swea7465.py: -------------------------------------------------------------------------------- 1 | def dfs(curr): 2 | visited.add(curr) 3 | for next in edge[curr]: 4 | if next in visited: 5 | continue 6 | dfs(next) 7 | 8 | T = int(input()) 9 | for t in range(1, T + 1): 10 | N, M = map(int, input().split()) 11 | edge = dict() 12 | for start in range(1, N + 1): 13 | edge[start] = [] 14 | for _ in range(M): 15 | s, e = map(int, input().split()) 16 | edge[s].append(e) 17 | edge[e].append(s) 18 | visited = set() 19 | group = 0 20 | for start in range(1, N + 1): 21 | if start in visited: 22 | continue 23 | dfs(start) 24 | group += 1 25 | print(f'#{t} {group}') -------------------------------------------------------------------------------- /seoul_21_minjaekim/MinCoding/Algorithm Tower/Backtracking Tower/9/min_backtracking_tower_9.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | bool goodString(int N, string str = "") { 6 | for (int i = 1; i <= str.size() / 2; i++) 7 | if (str.substr(str.size() - i, i) == str.substr(str.size() - 2 * i, i)) 8 | return false; 9 | if (str.size() == N) { 10 | cout << str << '\n'; 11 | return true; 12 | } 13 | 14 | for (int i = 0; i < 3; i++) 15 | if (goodString(N, str + char('1' + i))) 16 | return true; 17 | return false; 18 | } 19 | 20 | int main() { 21 | ios_base::sync_with_stdio(false); 22 | cin.tie(nullptr); 23 | cout.tie(nullptr); 24 | 25 | int N; 26 | cin >> N; 27 | goodString(N); 28 | } -------------------------------------------------------------------------------- /seoul_21_minjaekim/MinCoding/Algorithm Tower/Backtracking Tower/9/README.md: -------------------------------------------------------------------------------- 1 | # [알고리즘 탑] Backtracking의 탑 9번 - 좋은수열 2 | 3 | ## 카테고리 4 | 5 | Backtracking, 재귀 6 | 7 | ## 시간복잡도 8 | 9 | O(3^N) 10 | 11 | ## 해설 12 | 13 | 입력받은 문자의 뒤에 1~3을 붙여가며 재귀를 돈다. 14 | 15 | ```cpp 16 | for (int i = 0; i < 3; i++) 17 | if (goodString(N, str + char('1' + i))) 18 | return true; 19 | ``` 20 | 21 | 새로 붙은 문자열이 좋은 문자열인지 확인한다. 22 | 23 | ```cpp 24 | for (int i = 1; i <= str.size() / 2; i++) 25 | if (str.substr(str.size() - i, i) == str.substr(str.size() - 2 * i, i)) 26 | return false; 27 | ``` 28 | 29 | 문자열이 목표 길이에 도달했다면, 문자열을 출력하고 true를 반환해 재귀를 종료한다. 30 | 31 | ```cpp 32 | if (str.size() == N) { 33 | cout << str << '\n'; 34 | return true; 35 | } 36 | ``` 37 | 38 | ## 성능 요약 39 | 40 | 메모리: 2 MB, 시간: 1 ms -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/도움-요청.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 도움 요청 3 | about: 도움 요청 템플릿 4 | title: "[도움 요청] " 5 | labels: HELP 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## 📝 Question 11 | 12 | 17 | 18 | ## 🤯 Problem 19 | 20 | 21 | ## 🤔 What I've tried 22 | 23 | 24 | 25 | ## 🖥️ code 26 | 27 | 28 | 39 | -------------------------------------------------------------------------------- /seoul_21_minjaekim/Softeer/HSAT_7th/1/HSAT_7th_1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int main(int argc, char** argv) 8 | { 9 | ios_base::sync_with_stdio(false); 10 | cin.tie(nullptr); 11 | cout.tie(nullptr); 12 | 13 | int n, q; 14 | cin >> n >> q; 15 | 16 | int cars[50000]; 17 | for (int i = 0; i < n; ++i) 18 | cin >> cars[i]; 19 | 20 | sort(cars, cars + n); 21 | 22 | unordered_map map; 23 | for (int i = 0; i < n; ++i) 24 | map[cars[i]] = i + 1; 25 | 26 | for (int i = 0; i < q; ++i) { 27 | int m, m_idx; 28 | cin >> m; 29 | m_idx = map[m]; 30 | cout << (m_idx ? (m_idx - 1) * (n - m_idx) : m_idx) << '\n'; 31 | } 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /seoul_21_minjaekim/SWEA/D2/swea1204/swea1204.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ios_base::sync_with_stdio(false); 7 | cin.tie(nullptr); 8 | cout.tie(nullptr); 9 | 10 | int T; 11 | cin >> T; 12 | for (int test_case = 1; test_case <= T; ++test_case) 13 | { 14 | int tc_num, max_score = 0, result; 15 | cin >> tc_num; 16 | 17 | int scores[101] = { 0 }; 18 | 19 | for (int i = 0; i < 1000; i++) { 20 | int score; 21 | cin >> score; 22 | scores[score]++; 23 | if (scores[score] >= max_score) { 24 | max_score = scores[score]; 25 | result = score; 26 | } 27 | } 28 | 29 | cout << "#" << test_case << " " << result << '\n'; 30 | } 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /seoul_x_hwijoonchoi/BOJ/boj20529/boj20529.py: -------------------------------------------------------------------------------- 1 | from itertools import combinations 2 | def mbti_dis(lst): 3 | dis = 8 4 | dic = {} 5 | for mbti in lst: # 딕셔너리에 저장 6 | if mbti not in dic.keys(): 7 | dic[mbti] = 1 8 | else: 9 | dic[mbti] += 1 10 | if dic[mbti] == 3: # 같은 MBTI가 3개가 되면 거리 0 11 | dis = 0 12 | return dis 13 | # 같은 MBTI 2개 이하 14 | cnt = 0 15 | for mbti in combinations(lst,3): #[(1,2,3),(3,4,5)] 16 | cnt = 0 17 | for mbti_xy in combinations(mbti,2): 18 | x,y = mbti_xy 19 | for i in range(4): 20 | if x[i] != y[i]: 21 | cnt += 1 22 | dis = min(dis, cnt) 23 | return dis 24 | 25 | T = int(input()) 26 | for _ in range(T): 27 | N = int(input()) 28 | lst = list(input().split()) 29 | print(mbti_dis(lst)) -------------------------------------------------------------------------------- /seoul_21_minjaekim/MinCoding/Algorithm Tower/DAT Tower/12/min_dat_tower_12.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ios_base::sync_with_stdio(false); 7 | cin.tie(nullptr); 8 | cout.tie(nullptr); 9 | 10 | int N, K; 11 | cin >> N >> K; 12 | 13 | int arr[5000]; 14 | bool isIn[100001] = { false }; 15 | for (int i = 0; i < N; ++i) { 16 | cin >> arr[i]; 17 | isIn[arr[i]] = true; 18 | } 19 | 20 | int cnt = 0; 21 | for (int i = 0; i < N; ++i) { 22 | if (arr[i] > K) continue; 23 | for (int j = i + 1; j < N; ++j) { 24 | int need_num = K - arr[i] - arr[j]; 25 | if (need_num < 0 or 100000 < need_num or need_num == arr[i] or need_num == arr[j]) continue; 26 | cnt += isIn[need_num]; 27 | } 28 | } 29 | 30 | cout << cnt / 3 << '\n'; 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /seoul_21_minjaekim/SWEA/D2/swea1204/README.md: -------------------------------------------------------------------------------- 1 | # [[D2] [S/W 문제해결 기본] 1일차 - 최빈수 구하기 - 1204](https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV13zo1KAAACFAYh) 2 | 3 | ## 카테고리 4 | 5 | 최빈값, DP 6 | 7 | ## 시간복잡도 8 | 9 | 학생의 수와 점수의 범위가 상수이기 때문에 시간복잡도는 O(1)이다. 10 | 11 | ## 풀이 12 | 13 | 메모이제이션을 이용해 입력받은 값을 인덱스로 배열 요소에 빈도를 카운트한다. 14 | 역대 최고 빈도보다 높은 빈도로 등장한 점수가 있으면 해당 점수를 저장한다. 15 | 16 | ```cpp 17 | int tc_num, max_score = 0, result; 18 | cin >> tc_num; 19 | 20 | int scores[101] = { 0 }; 21 | 22 | for (int i = 0; i < 1000; i++) { 23 | int score; 24 | cin >> score; 25 | scores[score]++; 26 | if (scores[score] >= max_score) { 27 | max_score = scores[score]; 28 | result = score; 29 | } 30 | } 31 | ``` 32 | 33 | 결과를 출력한다. 34 | 35 | ```cpp 36 | cout << "#" << test_case << " " << result << '\n'; 37 | ``` 38 | 39 | ## 성능 요약 40 | 41 | 메모리: 13,536 KB, 시간: 6 ms, 코드길이: 676 Bytes 42 | -------------------------------------------------------------------------------- /seoul_x_hwijoonchoi/BOJ/boj7490/README.md: -------------------------------------------------------------------------------- 1 | # [BoJ 20529 부르트포스](https://www.acmicpc.net/problem/20529) 2 | 3 | solved.ac Gold 5 4 | 5 | ## 카테고리 6 | 7 | 부르트포스, 백트래킹 8 | 9 | ## 시간복잡도 10 | 11 | 백트래킹을 사용하여 O(N!) 12 | 13 | ## 풀이 14 | 15 | 1. 모든 경우의 수를 아스키코드 순서에 맞게 따져 보아야 한다. 16 | 2. eval()이라는 파이썬 내장함수를 사용하면 문자열을 숫자로 직접 바꾸지 않고도 그 값을 계산할 수 있다. 17 | 18 | ```python 19 | # 2. 0만드는 백트래킹 함수 구현 20 | def make_zero(depth,seq): 21 | if depth == n: 22 | sequence = seq.replace(' ','') 23 | if eval(sequence) == 0: 24 | print(seq) 25 | return 26 | 27 | make_zero(depth+1,seq+' '+str(depth+1)) 28 | make_zero(depth+1,seq+'+'+str(depth+1)) 29 | make_zero(depth+1,seq+'-'+str(depth+1)) 30 | 31 | # 1. 입력받기 32 | t = int(input()) # test case 33 | 34 | for _ in range(t): 35 | n = int(input()) 36 | make_zero(1,'1') 37 | print('') 38 | ``` 39 | 40 | ## 결과 41 | 42 | 결과 : [맞았습니다!!](https://www.acmicpc.net/source/64036611) 43 | -------------------------------------------------------------------------------- /seoul_x_hwijoonchoi/BOJ/boj1431/boj1431.py: -------------------------------------------------------------------------------- 1 | # 1431 시리얼 번호 2 | 3 | 4 | n = int(input()) 5 | serial = [input() for _ in range(n)] 6 | 7 | from functools import cmp_to_key 8 | 9 | def compare(a,b): 10 | len_a = len(a) 11 | len_b = len(b) 12 | num = ['0','1','2','3','4','5','6','7','8','9'] 13 | # 첫번째 조건 14 | if len_a > len_b: # a가 큰데 자리를 바꾸면 큰 값이 뒤로 오게 정렬됨 15 | return 1 16 | elif len_a < len_b: 17 | return -1 18 | 19 | # 두번째 조건 20 | cnt_a = 0 21 | cnt_b = 0 22 | for i in range(len_a): 23 | if a[i] in num: 24 | cnt_a += int(a[i]) 25 | if b[i] in num: 26 | cnt_b += int(b[i]) 27 | if cnt_a > cnt_b: 28 | return 1 29 | elif cnt_a < cnt_b: 30 | return -1 31 | # 세번째 조건 32 | if a > b: 33 | return 1 34 | else: 35 | return -1 36 | 37 | 38 | serial = sorted(serial, key = cmp_to_key(compare)) 39 | 40 | for temp in serial: 41 | print(temp) 42 | -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Silver II/BoJ 6884/README.md: -------------------------------------------------------------------------------- 1 | # [백준 6884 소수 부분 수열](https://www.acmicpc.net/problem/6884) 2 | 3 | solved.ac Silver II 4 | 5 | ## 카테고리 6 | 7 | 수학, 브루트포스, 정수론, 누적합, 소수 판정, 에라토스테네스의 체 8 | 9 | ## 시간복잡도 10 | 11 | 단어 길이를 1씩 늘려가는 반복문에서 O(n) 12 | 검사를 시작하는 인덱스를 1씩 움직이면서 O(n) 13 | 총 O(n^2) 알고리즘이다. 14 | 수열의 길이는 최대 10000이므로 worst case의 경우 100,000,000번 연산한다(보통 1초로 추정). 테스트 케이스는 최대 20개이다. 15 | 5초안에 통과 못할 수도 있을 것이라 생각했는데 다행히 넘어갔다. 16 | 17 | ## 풀이 18 | 19 | 부분 수열에 대한 누적합을 이중 포문 안에서 하나하나 더하면 O(n ^ 3)이라는 지옥에서 온 알고리즘이 탄생한다. 20 | 따라서 이를 피하기 위해 입력 단계에서 미리 누적합을 구해놓았다. 21 | 22 | ```java 23 | int[] sum = new int[len + 1]; 24 | 25 | for (int i = 1; i <= len; i++) { 26 | sum[i] += sum[i - 1] + Integer.parseInt(st.nextToken()); 27 | } 28 | ``` 29 | 이렇게 되면 나중에 누적합을 부분수열의 길이와 시작하는 인덱스만으로 O(1) 연산을 통해 구할 수 있다. 30 | ```java 31 | int temp = sum[start + curLen - 1] - sum[start - 1]; // temp는 부분 수열의 누적합 32 | ``` 33 | 34 | 그 밖의 로직은 간단하므로 생략한다. 35 | 36 | ## 결과 37 | 38 | 결과 : [맞았습니다!!](https://www.acmicpc.net/source/63587932) 39 | -------------------------------------------------------------------------------- /seoul_21_minjaekim/SWEA/D2/swea1961/README.md: -------------------------------------------------------------------------------- 1 | # [[D2] 숫자 배열 회전 - 1961](https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5Pq-OKAVYDFAUq) 2 | 3 | ## 카테고리 4 | 5 | 배열 6 | 7 | ## 시간복잡도 8 | 9 | 입력 행렬을 읽고, 출력하려면 각 요소를 한번씩 방문해야 하므로 시간복잡도는 O(N^2)이다. 10 | 11 | ## 풀이 12 | 13 | 행렬을 입력받는다. 14 | 15 | ```cpp 16 | int N; 17 | cin >> N; 18 | 19 | vector> matrix(N, vector(N)); 20 | for (vector& row : matrix) 21 | for (int& element : row) 22 | cin >> element; 23 | ``` 24 | 25 | 90도, 180도, 270도 회전시킨 행렬을 순서대로 출력한다. 26 | 27 | ```cpp 28 | cout << '#' << test_case << '\n'; 29 | for (int i = 0; i < N; ++i) { 30 | for (int j = N - 1; j >= 0; --j) 31 | cout << matrix[j][i]; 32 | cout << ' '; 33 | 34 | for (int j = N - 1; j >= 0; --j) 35 | cout << matrix[N - i - 1][j]; 36 | cout << ' '; 37 | 38 | for (int j = 0; j < N; ++j) 39 | cout << matrix[j][N - i - 1]; 40 | cout << '\n'; 41 | ``` 42 | 43 | ## 성능 요약 44 | 45 | 메모리: 4,256 KB, 시간: 6 ms, 코드길이: 895 Bytes 46 | -------------------------------------------------------------------------------- /seoul_21_jongilchoi/mincodding/dat_12/README.md: -------------------------------------------------------------------------------- 1 | # [세수의 합] 2 | 3 | ## 카테고리 4 | 5 | DAT 6 | 7 | ## 풀이 8 | 9 | 카운터로 사용할 변수 count를 선언해준다. 10 | ``` 11 | int count = 0; 12 | sort(arr.begin(), arr.end()); // 배열을 오름차순으로 정렬 13 | ``` 14 | 15 | 16 | 투포인터를 이용하여 원하는 값 K가 나왔을경우 변수 count에 1씩 추가한다. 17 | 18 | ```cpp 19 | for (int i = 0; i < N - 2; i++) { 20 | int left = i + 1; 21 | int right = N - 1; 22 | 23 | while (left < right) { 24 | int sum = arr[i] + arr[left] + arr[right]; 25 | if (sum == K) { 26 | count++; 27 | left++; // 다음 가능한 조합 탐색 28 | right--; 29 | } 30 | else if (sum < K) { 31 | left++; // 더 큰 값을 만들기 위해 왼쪽 포인터 이동 32 | } 33 | else { 34 | right--; // 더 작은 값을 만들기 위해 오른쪽 포인터 이동 35 | } 36 | } 37 | } 38 | ``` 39 | 40 | 41 | 메인 함수에서 count 를 출력한다. 42 | 43 | ``` 44 | int result = countCombinations(arr, K); 45 | cout << result << endl; 46 | ``` -------------------------------------------------------------------------------- /seoul_21_minjaekim/MinCoding/Algorithm Tower/DAT Tower/12/README.md: -------------------------------------------------------------------------------- 1 | # [알고리즘 탑] DAT의 탑 12번 - 세 수의 합 2 | 3 | ## 카테고리 4 | 5 | DAT 6 | 7 | ## 시간복잡도 8 | 9 | 2중 반복문을 이용해 두 수의 합이 가능한 조합을 구하기 때문에, 시간복잡도는 `O(N^2)`이다. 10 | 11 | ## 풀이 12 | 13 | 입력받은 값이 존재하는지 O(1)으로 확인하기 위해 `isIn` 배열을 만든다. 14 | 15 | ```cpp 16 | int arr[5000]; 17 | bool isIn[100001] = { false }; 18 | for (int i = 0; i < N; ++i) { 19 | cin >> arr[i]; 20 | isIn[arr[i]] = true; 21 | } 22 | ``` 23 | 24 | `arr`에서 두 수의 합의 경우까지는 브루트 포스로 구한다. 25 | 두 수가 정해지면 마지막 수는 계산을 할 수 있으므로`need_num`을 구하고 `isIn` 배열을 이용해 만들 수 있는지 확인한다. 26 | 27 | ```cpp 28 | int cnt = 0; 29 | for (int i = 0; i < N; ++i) { 30 | if (arr[i] > K) continue; 31 | for (int j = i + 1; j < N; ++j) { 32 | int need_num = K - arr[i] - arr[j]; 33 | if (need_num < 0 or 100000 < need_num or need_num == arr[i] or need_num == arr[j]) continue; 34 | cnt += isIn[need_num]; 35 | } 36 | } 37 | ``` 38 | 39 | 같은 조합이 순서만 다른 경우를 제외하기 위해 3으로 나눠준다. 40 | 41 | ```cpp 42 | cout << cnt / 3 << '\n'; 43 | ``` 44 | 45 | ## 성능 요약 46 | 47 | 메모리: 2 MB, 시간: 33 ms 48 | -------------------------------------------------------------------------------- /seoul_21_minjaekim/SWEA/D2/swea1961/swea1961.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main() { 7 | ios_base::sync_with_stdio(false); 8 | cin.tie(nullptr); 9 | cout.tie(nullptr); 10 | 11 | int T; 12 | cin >> T; 13 | for (int test_case = 1; test_case <= T; ++test_case) 14 | { 15 | int N; 16 | cin >> N; 17 | 18 | vector> matrix(N, vector(N)); 19 | for (vector& row : matrix) 20 | for (int& element : row) 21 | cin >> element; 22 | 23 | cout << '#' << test_case << '\n'; 24 | for (int i = 0; i < N; ++i) { 25 | for (int j = N - 1; j >= 0; --j) 26 | cout << matrix[j][i]; 27 | cout << ' '; 28 | 29 | for (int j = N - 1; j >= 0; --j) 30 | cout << matrix[N - i - 1][j]; 31 | cout << ' '; 32 | 33 | for (int j = 0; j < N; ++j) 34 | cout << matrix[j][N - i - 1]; 35 | cout << '\n'; 36 | } 37 | } 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 SSAFY-10th 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /seoul_21_minjaekim/SWEA/D2/swea1959/swea1959.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main() { 7 | ios_base::sync_with_stdio(false); 8 | cin.tie(nullptr); 9 | cout.tie(nullptr); 10 | 11 | int T; 12 | cin >> T; 13 | for (int test_case = 1; test_case <= T; ++test_case) 14 | { 15 | int N, M, result = INT_MIN; 16 | cin >> N >> M; 17 | 18 | int* A = new int[N]; 19 | int* B = new int[M]; 20 | 21 | for (int i = 0; i < N; ++i) 22 | cin >> A[i]; 23 | for (int i = 0; i < M; ++i) 24 | cin >> B[i]; 25 | 26 | if (M > N) { 27 | swap(M, N); 28 | swap(A, B); 29 | } 30 | 31 | for (int offset = 0; offset <= N - M; ++offset) { 32 | int sum = 0; 33 | for (int i = 0; i < M; i++) 34 | sum += A[i + offset] * B[i]; 35 | result = max(result, sum); 36 | } 37 | 38 | delete[] A; 39 | delete[] B; 40 | 41 | cout << "#" << test_case << " " << result << '\n'; 42 | } 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /seoul_21_minjaekim/BoJ/Silver II/boj1260/boj1260.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from collections import defaultdict, deque 3 | 4 | 5 | def dfs(node): 6 | dfs_visited[node] = True 7 | 8 | visited_node = [node] 9 | for path in sorted(graph[node]): 10 | if not dfs_visited[path]: 11 | visited_node += dfs(path) 12 | 13 | return visited_node 14 | 15 | 16 | def bfs(start): 17 | bfs_visited[start] = True 18 | que = deque([start]) 19 | 20 | visited_node = [] 21 | while que: 22 | visited_node.append(que.popleft()) 23 | for node in sorted(graph[visited_node[-1]]): 24 | if not bfs_visited[node]: 25 | que.append(node) 26 | bfs_visited[node] = True 27 | 28 | return visited_node 29 | 30 | 31 | N, M, V = map(int, sys.stdin.readline().split()) 32 | graph = defaultdict(set) 33 | for _ in range(M): 34 | s, e = map(int, sys.stdin.readline().split()) 35 | graph[s].add(e) 36 | graph[e].add(s) 37 | 38 | dfs_visited = [False] * (N + 1) 39 | bfs_visited = [False] * (N + 1) 40 | 41 | sys.stdout.write(' '.join(map(str, dfs(V))) + "\n" + ' '.join(map(str, bfs(V)))) 42 | -------------------------------------------------------------------------------- /seoul_09_kyoohyunkim/BOJ/Gold III/boj 10986/Boj_10986.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.InputStreamReader; 3 | import java.util.StringTokenizer; 4 | 5 | 6 | public class Boj_10986 { 7 | 8 | static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 9 | static StringTokenizer st; 10 | public static void main(String[] args) throws Exception { 11 | st = new StringTokenizer(br.readLine()); 12 | int n = Integer.parseInt(st.nextToken()); 13 | int m = Integer.parseInt(st.nextToken()); 14 | 15 | long[] arr = new long[n + 1]; 16 | st = new StringTokenizer(br.readLine()); 17 | 18 | int[] mods = new int[m]; 19 | 20 | for (int i = 1; i <= n; i++) { 21 | arr[i] = (arr[i - 1] %m + Long.parseLong(st.nextToken())% m)% m; 22 | int num = (int)(arr[i] % m); 23 | mods[num]++; 24 | } 25 | long result = 0; 26 | for (int mod : mods) 27 | result += nCTwo(mod); 28 | result += mods[0]; 29 | System.out.println(result); 30 | } 31 | 32 | private static long nCTwo(long n) { 33 | return (n * (n-1))/2; 34 | } 35 | 36 | 37 | 38 | } -------------------------------------------------------------------------------- /seoul_x_hwijoonchoi/BOJ/boj1431/README.md: -------------------------------------------------------------------------------- 1 | # [BoJ 2194 bfs](https://www.acmicpc.net/problem/2194) 2 | 3 | solved.ac silver 3 4 | 5 | ## 카테고리 6 | 7 | 정렬 8 | 9 | ## 시간복잡도 10 | 11 | O(logn) 12 | 13 | ## 풀이 14 | 15 | ```python 16 | # 1431 시리얼 번호 17 | 18 | n = int(input()) 19 | serial = [input() for _ in range(n)] 20 | 21 | from functools import cmp_to_key 22 | 23 | def compare(a,b): 24 | len_a = len(a) 25 | len_b = len(b) 26 | num = ['0','1','2','3','4','5','6','7','8','9'] 27 | # 첫번째 조건 28 | if len_a > len_b: # a가 큰데 자리를 바꾸면 큰 값이 뒤로 오게 정렬됨 29 | return 1 30 | elif len_a < len_b: 31 | return -1 32 | 33 | # 두번째 조건 34 | cnt_a = 0 35 | cnt_b = 0 36 | for i in range(len_a): 37 | if a[i] in num: 38 | cnt_a += int(a[i]) 39 | if b[i] in num: 40 | cnt_b += int(b[i]) 41 | if cnt_a > cnt_b: 42 | return 1 43 | elif cnt_a < cnt_b: 44 | return -1 45 | # 세번째 조건 46 | if a > b: 47 | return 1 48 | else: 49 | return -1 50 | 51 | 52 | serial = sorted(serial, key = cmp_to_key(compare)) 53 | 54 | for temp in serial: 55 | print(temp) 56 | 57 | ``` 58 | 59 | ## 결과 60 | 61 | 결과 : [맞았습니다] -------------------------------------------------------------------------------- /seoul_21_minjaekim/BoJ/Gold IV/boj2602/boj2602.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ios_base::sync_with_stdio(false); 7 | cin.tie(nullptr); 8 | cout.tie(nullptr); 9 | 10 | string target, bridge[2]; 11 | cin >> target >> bridge[0] >> bridge[1]; 12 | 13 | int dp[2][20][100] = {0,}; 14 | 15 | for (int i = 0; i < 2; ++i) { 16 | for (int j = 0; j < target.size(); ++j) { 17 | int devil_or_angel = (i + j) % 2; 18 | if (j == 0) 19 | dp[i][0][0] = (target[0] == bridge[devil_or_angel][0]); 20 | for (int k = 1; k < int(bridge[i].size() - target.size()) + j + 1; ++k) { 21 | if (target[j] == bridge[devil_or_angel][k]) { 22 | if (j == 0) 23 | dp[i][j][k] = dp[i][j][k - 1] + 1; 24 | else 25 | dp[i][j][k] = dp[i][j][k - 1] + dp[i][j - 1][k - 1]; 26 | } 27 | else { 28 | dp[i][j][k] = dp[i][j][k - 1]; 29 | } 30 | } 31 | } 32 | } 33 | 34 | cout << dp[0][target.size() - 1][bridge[0].size() - 1] + dp[1][target.size() - 1][bridge[1].size() - 1] << '\n'; 35 | 36 | return 0; 37 | } -------------------------------------------------------------------------------- /seoul_21_minjaekim/SWEA/D2/swea1974/swea1974.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ios_base::sync_with_stdio(false); 7 | cin.tie(nullptr); 8 | cout.tie(nullptr); 9 | 10 | int T; 11 | cin >> T; 12 | for (int test_case = 1; test_case <= T; ++test_case) 13 | { 14 | bool row_check[9][9] = { false }; 15 | bool col_check[9][9] = { false }; 16 | bool square_check[9][9] = { false }; 17 | bool result = true; 18 | 19 | for (int row = 0; row < 9; row++) { 20 | for (int col = 0; col < 9; col++) { 21 | int slot; 22 | cin >> slot; 23 | if (!result) 24 | continue; 25 | int square = (row / 3) * 3 + col / 3; 26 | if (!row_check[row][slot - 1] and !col_check[col][slot - 1] and !square_check[square][slot - 1]) 27 | row_check[row][slot - 1] = col_check[col][slot - 1] = square_check[square][slot - 1] = true; 28 | else 29 | result = false; 30 | } 31 | } 32 | cout << '#' << test_case << ' ' << result << '\n'; 33 | } 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /seoul_21_minjaekim/SWEA/D2/swea1974/README.md: -------------------------------------------------------------------------------- 1 | # [[D2] 스도쿠 검증 - 1974](https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5Psz16AYEDFAUq) 2 | 3 | ## 카테고리 4 | 5 | DP 6 | 7 | ## 시간복잡도 8 | 9 | 스도쿠 크기가 고정되어 있으므로 시간복잡도는 O(1)이다. 10 | 11 | ## 풀이 12 | 13 | 메모이제이션을 위한 중복 체크 배열을 3가지 만들어준다. 14 | 15 | ```cpp 16 | bool row_check[9][9] = { false }; 17 | bool col_check[9][9] = { false }; 18 | bool square_check[9][9] = { false }; 19 | bool result = true; 20 | ``` 21 | 22 | 스도쿠의 각 슬롯의 값을 입력 받으며, 조건 체크를 진행한다. 23 | 24 | ```cpp 25 | for (int row = 0; row < 9; row++) { 26 | for (int col = 0; col < 9; col++) { 27 | int slot; 28 | cin >> slot; 29 | if (!result) 30 | continue; 31 | int square = (row / 3) * 3 + col / 3; 32 | if (!row_check[row][slot - 1] and !col_check[col][slot - 1] and !square_check[square][slot - 1]) 33 | row_check[row][slot - 1] = col_check[col][slot - 1] = square_check[square][slot - 1] = true; 34 | else 35 | result = false; 36 | } 37 | } 38 | ``` 39 | 40 | 결과를 출력한다. 41 | 42 | ```cpp 43 | cout << '#' << test_case << ' ' << result << '\n'; 44 | ``` 45 | 46 | ## 성능 요약 47 | 48 | 메모리: 13,536 KB, 시간: 5 ms, 코드길이: 1,033 Bytes 49 | -------------------------------------------------------------------------------- /seoul_21_minjaekim/SWEA/D2/swea1959/README.md: -------------------------------------------------------------------------------- 1 | # [[D2] 두 개의 숫자열 - 1959](https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5PpoFaAS4DFAUq) 2 | 3 | ## 카테고리 4 | 5 | 배열 6 | 7 | ## 시간복잡도 8 | 9 | 시간복잡도는 O(N + M + NM)이다. 10 | 11 | ## 풀이 12 | 13 | 배열을 입력받는다. 14 | O(N + M) 15 | 16 | ```cpp 17 | int N, M, result = INT_MIN; 18 | cin >> N >> M; 19 | 20 | int* A = new int[N]; 21 | int* B = new int[M]; 22 | 23 | for (int i = 0; i < N; ++i) 24 | cin >> A[i]; 25 | for (int i = 0; i < M; ++i) 26 | cin >> B[i]; 27 | ``` 28 | 29 | 두 배열 중 큰 배열을 A, N으로 설정한다. 30 | O(1) 31 | 32 | ```cpp 33 | if (M > N) { 34 | swap(M, N); 35 | swap(A, B); 36 | } 37 | ``` 38 | 39 | 두 배열의 내적을 계산한다. 40 | O((N - M + 1) * M) => O(NM) 41 | 42 | ```cpp 43 | for (int offset = 0; offset <= N - M; ++offset) { 44 | int sum = 0; 45 | for (int i = 0; i < M; i++) 46 | sum += A[i + offset] * B[i]; 47 | result = max(result, sum); 48 | } 49 | ``` 50 | 51 | 동적할당 된 배열을 할당 해제한다. 52 | O(1) 53 | 54 | ```cpp 55 | delete[] A; 56 | delete[] B; 57 | ``` 58 | 59 | 결과를 출력한다. 60 | O(1) 61 | 62 | ```cpp 63 | cout << "#" << test_case << " " << result << '\n'; 64 | ``` 65 | 66 | ## 성능 요약 67 | 68 | 메모리: 13,540 KB, 시간: 5 ms, 코드길이: 910 Bytes 69 | -------------------------------------------------------------------------------- /seoul_21_minjaekim/MinCoding/Algorithm Tower/Backtracking Tower/8/README.md: -------------------------------------------------------------------------------- 1 | # [알고리즘 탑] Backtracking의 탑 8번 - 다빈치 타워 2 | 3 | ## 카테고리 4 | 5 | DAT, Backtracking, 재귀 6 | 7 | ## 시간복잡도 8 | 9 | O(M^N * N) 10 | 11 | ## 해설 12 | 13 | 재귀로 계산하면서 나오는 값중 최대값을 계산해서 반환한다. 14 | 15 | ```cpp 16 | long long calcMaxDavinci(int depth = 0); 17 | ``` 18 | 19 | depth는 현재 깊이를 의미하는 변수다. depth가 M과 같아졌을 때 조합의 값을 계산한다. 20 | 21 | ```cpp 22 | if (depth == M) { 23 | ``` 24 | 25 | 각 세로 열을 순회하며 수를 뽑는 과정을 수행한다. 26 | 27 | ```cpp 28 | for (int i = 0; i < M; ++i) { 29 | int sum = 0; 30 | bool isIn[201] = { false }; 31 | for (int j = 0; j < N; ++j) { 32 | int value = arr[j][(i + start_idxs[j]) % M]; 33 | ``` 34 | 35 | isIn[] 배열을 이용해 수의 중복을 확인하고 중복이 발생하면 최소값인 -pow(100 * N, M) 값을 반환한다. 36 | 37 | ```cpp 38 | if (isIn[value + 100]) 39 | return -pow(100 * N, M); 40 | ``` 41 | 42 | 각 세로 열의 합들을 곱한다. 모든 세로 열을 순회 한 뒤 davinci를 반환한다. 43 | 44 | ```cpp 45 | davinci *= sum; 46 | ``` 47 | 48 | 재귀를 돌면서 반환된 값 중 최대값을 구해서 반환한다. 49 | 50 | ```cpp 51 | long long max_davinci = -pow(100 * N, M); 52 | for (int i = 0; i < M; ++i) { 53 | start_idxs[depth] = i; 54 | max_davinci = max(calcMaxDavinci(depth + 1), max_davinci); 55 | } 56 | return max_davinci; 57 | ``` 58 | 59 | ## 성능 요약 60 | 61 | 메모리: 2 MB, 시간: 2 ms -------------------------------------------------------------------------------- /seoul_21_minjaekim/BoJ/Gold I/boj2098/boj2098.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int n; 8 | int graph[16][16]; 9 | int memo[16][1 << 16]; 10 | short finish; 11 | 12 | int dfs(int current = 0, short visited = 1) { 13 | if (visited == finish) 14 | return graph[current][0]; 15 | 16 | if (memo[current][visited]) 17 | return memo[current][visited]; 18 | 19 | memo[current][visited] = INT_MAX; 20 | for (int i = 0; i < n; ++i) { 21 | if (graph[current][i] and !(visited bitand (1 << i))) { 22 | int result = dfs(i, visited bitor (1 << i)); 23 | if (result and result != INT_MAX) 24 | memo[current][visited] = min(result + graph[current][i], memo[current][visited]); 25 | } 26 | } 27 | return memo[current][visited]; 28 | } 29 | 30 | void initial_graph() { 31 | finish = (1 << n) - 1; 32 | for (int i = 0; i < n; ++i) 33 | for (int j = 0; j < n; ++j) 34 | cin >> graph[i][j]; 35 | } 36 | 37 | int main() { 38 | ios_base::sync_with_stdio(false); 39 | cin.tie(nullptr); 40 | cout.tie(nullptr); 41 | 42 | cin >> n; 43 | initial_graph(); 44 | cout << dfs() << '\n'; 45 | 46 | return 0; 47 | } -------------------------------------------------------------------------------- /seoul_21_jongilchoi/mincodding/dat_12/dat_12.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int countCombinations(vector& arr, int K) { 8 | int count = 0; 9 | sort(arr.begin(), arr.end()); // 배열을 오름차순으로 정렬 10 | 11 | int N = arr.size(); 12 | for (int i = 0; i < N - 2; i++) { 13 | int left = i + 1; 14 | int right = N - 1; 15 | 16 | while (left < right) { 17 | int sum = arr[i] + arr[left] + arr[right]; 18 | if (sum == K) { 19 | count++; 20 | left++; // 다음 가능한 조합 탐색 21 | right--; 22 | } 23 | else if (sum < K) { 24 | left++; // 더 큰 값을 만들기 위해 왼쪽 포인터 이동 25 | } 26 | else { 27 | right--; // 더 작은 값을 만들기 위해 오른쪽 포인터 이동 28 | } 29 | } 30 | } 31 | 32 | return count; 33 | } 34 | 35 | int main() { 36 | int N, K; 37 | 38 | cin >> N >> K; 39 | 40 | vector arr(N); 41 | 42 | for (int i = 0; i < N; i++) { 43 | cin >> arr[i]; 44 | } 45 | 46 | int result = countCombinations(arr, K); 47 | cout << result << endl; 48 | 49 | return 0; 50 | } -------------------------------------------------------------------------------- /seoul_x_hwijoonchoi/BOJ/boj20529/README.md: -------------------------------------------------------------------------------- 1 | # [BoJ 20529 부르트포스](https://www.acmicpc.net/problem/20529) 2 | 3 | solved.ac Silver 1 4 | 5 | ## 카테고리 6 | 7 | 부르트포스 8 | 9 | ## 시간복잡도 10 | 11 | 같은 MBTI가 2개 이하일 때, 2중 for문을 돌아야 하므로 시간 복잡도는 O(N^2)이다. 12 | 13 | ## 풀이 14 | 15 | 1. 딕셔너리에 mbti별로 저장해서 3개 이상일 때 거리 0이 되도록함 16 | 2. 그 외는 전부 계산해 봐야 하므로 조합(combinations)사용 17 | 18 | ```python 19 | from itertools import combinations 20 | def mbti_dis(lst): 21 | dis = 8 22 | dic = {} 23 | for mbti in lst: # 딕셔너리에 저장 24 | if mbti not in dic.keys(): 25 | dic[mbti] = 1 26 | else: 27 | dic[mbti] += 1 28 | if dic[mbti] == 3: # 같은 MBTI가 3개가 되면 거리 0 29 | dis = 0 30 | return dis 31 | # 같은 MBTI 2개 이하 32 | cnt = 0 33 | for mbti in combinations(lst,3): #[(1,2,3),(3,4,5)] 34 | cnt = 0 35 | for mbti_xy in combinations(mbti,2): 36 | x,y = mbti_xy 37 | for i in range(4): 38 | if x[i] != y[i]: 39 | cnt += 1 40 | if cnt < dis: 41 | dis = cnt 42 | return dis 43 | 44 | T = int(input()) 45 | for _ in range(T): 46 | N = int(input()) 47 | lst = list(input().split()) 48 | print(mbti_dis(lst)) 49 | ``` 50 | 51 | ## 결과 52 | 53 | 결과 : [맞았습니다!!](https://www.acmicpc.net/source/62701318) 54 | -------------------------------------------------------------------------------- /seoul_18_kimjeonguk/BOJ/SILVER III/11478 - 서로 다른 부분 문자열의 개수/readme.md: -------------------------------------------------------------------------------- 1 | # [BOJ 11478 서로 다른 부분 문자열의 개수](https://www.acmicpc.net/problem/11478) 2 | 3 | Silver 3 4 | 5 | ## 알고리즘 분류 6 | 7 | - 자료구조 8 | - 문자열 9 | - 해시를 사용한 집합과 맵 10 | - 트리를 사용한 집합과 맵 11 | 12 | ## 풀이 13 | 14 |
15 | 스포일러 주의 16 |
17 | 18 | --- 19 | 20 | 문자열 S가 주어졌을 때, S의 **서로 다른 문자열**의 개수를 구하는 프로그램을 작성해야합니다. 21 | 여기서 **서로 다른 문자열**이란 `ababc`라는 문자열이 주어졌을 때 `a, b, a, b, c, ab, ba, ab, bc, aba, bab, abc, abab, babc, ababc` 에서 **중복되지 않은 문자열**을 뜻합니다. 22 | 예를 들면 `a` 라는 문자열은 3개가 있지만 **서로 다른 문자열**을 원하기 때문에 1개로 계산을 해야합니다. 23 | 24 | 위와 같이 문제를 분석한 뒤 가장 먼저 해야할 일은 문자열을 분리하는 로직을 작성해야 합니다. 25 | 문자열을 분리하기 위한 함수로 `substring`을 사용하며 반복문을 활용하였습니다. 26 | 27 | ```java 28 | for (int i = 0; i < s.length(); i++) { 29 | for (int j = i + 1; j <= s.length(); j++) { 30 | set.add(s.substring(i, j)); 31 | } 32 | } 33 | ``` 34 | 35 | 문자열을 분리 한 뒤 중복 없이 저장하기 위한 자료구조를 사용하기 위해서 `HashSet`을 사용하였습니다. 36 | `List`와 같은 자료구조는 중복을 방지하기 위해서 해당 값이 있는지 확인을 하기 위한 시간`O(N)`만큼의 시간이 걸리지만 `Set`은 `O(1)` 의 시간이 걸리기 때문에 매우 빠르고 중복을 허용하지 않습니다. 37 | 38 | 이러한 이유를 토대로 문자열을 분리 한 뒤 `HashSet`에 문자열을 중복 없이 저장 한 뒤 컬렉션의 사이즈를 반환하여 출력하였습니다. 39 | 40 |
41 |
42 | 43 | ## 체점 결과 44 | 45 | ![11478](https://github.com/SSAFY-10th/algorithm/assets/74192619/c38ac9ec-b471-4243-9b82-f3b4387fe5d1) 46 | -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Silver I/BoJ 9465/Baekjoon_9465.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.StringTokenizer; 5 | 6 | public class Baekjoon_9465 { 7 | 8 | public static void main(String[] args) throws IOException { 9 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 10 | int T = Integer.parseInt(br.readLine()); 11 | for (int test_case = 1; test_case <= T; test_case++) { 12 | 13 | int n = Integer.parseInt(br.readLine()); 14 | int[][] map = new int[2][n + 1]; 15 | for (int i = 0; i < 2; i++) { 16 | StringTokenizer st = new StringTokenizer(br.readLine()); 17 | for (int j = 1; j <= n; j++) { 18 | map[i][j] = Integer.parseInt(st.nextToken()); 19 | } 20 | } 21 | 22 | int[][] dp = new int[2][n + 1]; 23 | dp[0][1] = map[0][1]; 24 | dp[1][1] = map[1][1]; 25 | 26 | for (int i = 2; i <= n; i++) { 27 | dp[0][i] = Math.max(dp[1][i - 2], dp[1][i - 1]) + map[0][i]; 28 | dp[1][i] = Math.max(dp[0][i - 2], dp[0][i - 1]) + map[1][i]; 29 | } 30 | 31 | int result = Math.max(dp[0][n], dp[1][n]); 32 | System.out.println(result); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Platinum V/Boj 3015/Baekjoon_3015.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.Stack; 5 | 6 | public class Baekjoon_3015 { 7 | 8 | static class Man { 9 | int duplicate; 10 | int height; 11 | 12 | Man(int duplicate, int height) { 13 | this.duplicate = duplicate; 14 | this.height = height; 15 | } 16 | } 17 | 18 | public static void main(String[] args) throws IOException { 19 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 20 | int N = Integer.parseInt(br.readLine()); 21 | 22 | Stack stack = new Stack<>(); 23 | long result = 0; 24 | for(int i = 0;i < N; i++) { 25 | 26 | int height = Integer.parseInt(br.readLine()); 27 | int duplicate = 1; 28 | while(!stack.empty() && stack.peek().height <= height) { 29 | Man man = stack.pop(); 30 | result += man.duplicate; 31 | 32 | if(man.height == height) { 33 | duplicate += man.duplicate; 34 | } 35 | } 36 | 37 | if(!stack.isEmpty()) 38 | result++; 39 | 40 | stack.push(new Man(duplicate, height)); 41 | } 42 | 43 | System.out.println(result); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Silver III/boj11140/README.md: -------------------------------------------------------------------------------- 1 | # [백준 11140 LOL](https://www.acmicpc.net/problem/11140) 2 | 3 | solved.ac Silver III 4 | 5 | ## 카테고리 6 | 7 | 문자열, 구현, case_work 8 | 9 | ## 시간복잡도 10 | 11 | 테스트 케이스를 하나씩 순회하면서 O(n) 12 | 길이가 1부터 3까지인 서브스트링으로 쪼개서 조건을 검사하면서 O(n) 13 | 총 O(n^2)으로 시간복잡도에서 유리한 알고리즘은 아니지만 14 | 테스트케이스가 최대 100개, 한 단어 당 최대 길이는 50글자이므로 충분히 1초 안에 통과 가능하다. 15 | 16 | ## 풀이 17 | 18 | 단어를 길이가 1부터 3까지인 substring 쪼개서 조건을 세운다. 19 | 조건을 *순서에 맞게* 배치한다면 모든 상황을 고려한 답을 도출할 수 있다. 20 | 21 | 조건 1. 단어에 "o"나 "l"이 있으면 문자를 2개 추가하는 것으로 lol을 만들 수 있다. 22 | ```java 23 | if(temp.equals("o") || (temp.equals("l"))) result = 2; 24 | ``` 25 | 26 | 조건 2. 단어에 "lo"나 "ol", "ll"이 있으면 문자를 1개 추가하는 것으로 lol을 만들 수 있다. 27 | ```java 28 | if(temp.equals("lo") || temp.equals("ol") || temp.equals("ll")) result = 1; 29 | ``` 30 | 31 | 조건 3. "l"과 "l" 사이에 문자가 하나 있다면 이를 제거하는 것으로 lol을 만들 수 있다. 32 | ```java 33 | String REGEXP_PATTERN_STRING = "[a-z]*l[a-z]l[a-z]*"; 34 | if(Pattern.matches(REGEXP_PATTERN_STRING, temp)) result = 1; 35 | ``` 36 | 37 | 조건 4. 단어에 "lol"이 있으면 무조건 결과는 0이다. 38 | ```java 39 | if(temp.equals("lol")) result = 0; 40 | ``` 41 | 42 | ## 결과 43 | 44 | 결과 : [맞았습니다!!](http://boj.kr/34fe82abdd904b09bbbf7943d8376185) 45 | 46 | ## 추신 47 | 48 | 40분 걸렸음. 문자열이 너무 약점이다. 49 | 정규표현식 좀 확실하게 알아야할 것 같다.. 50 | 로직 구현하고 정규표현식을 사용해야 하는 예외 상황까지 생각나는데 20분정도 소요됐는데 정작 정규표현식 쓰는데 너무 헤매서 결국 서칭하고 20분이 더 걸렸다. 51 | 문자열 푸는데 정규표현식 제대로 모르면 너무 힘들다.. 따로 공부좀 하자. -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Silver II/BoJ 1138/Baekjoon_1138.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.StringTokenizer; 5 | 6 | public class Baekjoon_1138 { 7 | 8 | public static void main(String[] args) throws IOException{ 9 | 10 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 11 | 12 | //입력 13 | int N = Integer.parseInt(br.readLine()); 14 | int[] arr = new int[N + 1]; 15 | StringTokenizer st = new StringTokenizer(br.readLine()); 16 | for (int i = 1; i <= N; i++) { 17 | arr[i] = Integer.parseInt(st.nextToken()); 18 | } 19 | 20 | // 자료구조 선택 21 | int[] result = new int[N + 1]; 22 | 23 | // 구현 24 | for (int height = 1; height <= N; height++) { 25 | int left = arr[height]; 26 | int idx = 0, cnt = 0; 27 | while (cnt != left) { 28 | if(result[idx] == 0) cnt++; 29 | idx++; 30 | } 31 | while(result[idx] != 0) { 32 | idx++; 33 | } 34 | result[idx] = height; 35 | } 36 | 37 | // 출력 38 | StringBuilder sb = new StringBuilder(); 39 | for (int i = 0; i < N; i++) { 40 | sb.append(result[i]).append(" "); 41 | } 42 | System.out.println(sb); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /seoul_21_minjaekim/BoJ/Gold I/boj2098/README.md: -------------------------------------------------------------------------------- 1 | # [BoJ 2098 외판원 순회](https://www.acmicpc.net/problem/2098) 2 | 3 | ## 카테고리 4 | 5 | 다이나믹 프로그래밍, 비트마스킹, 비트필드를 이용한 다이나믹 프로그래밍, 외판원 순회 문제 6 | 7 | ## 시간복잡도 8 | 9 | O(n * 2^n) 10 | 11 | ## 해설 12 | 13 | 노드의 개수에 따라서 완료시의 비트필드 형태를 설정하고, 그래프의 인접행렬을 입력받는다. 14 | 15 | ```cpp 16 | void initial_graph() { 17 | finish = (1 << n) - 1; 18 | for (int i = 0; i < n; ++i) 19 | for (int j = 0; j < n; ++j) 20 | cin >> graph[i][j]; 21 | } 22 | ``` 23 | 24 | DFS 재귀문의 종료조건으로 비트필드가 완료 조건을 달성하면, 0번 노드로 돌아가는 거리를 반환한다. 25 | 26 | ```cpp 27 | if (visited == finish) 28 | return graph[current][0]; 29 | ``` 30 | 31 | 이미 현재의 방문 상태와 동일한 상태에 대한 메모가 존재한다면, 그 값을 반환한다. 32 | 33 | ```cpp 34 | if (memo[current][visited]) 35 | return memo[current][visited]; 36 | ``` 37 | 38 | DFS를 통해 현재 노드에서 방문하지 않은 노드들을 방문하고, 그 노드들에서 0번 노드로 돌아가는 거리를 구한다. 39 | 그 중 최소값을 반환한다. 40 | 41 | ```cpp 42 | memo[current][visited] = INT_MAX; 43 | for (int i = 0; i < n; ++i) { 44 | if (graph[current][i] and !(visited bitand (1 << i))) { 45 | int result = dfs(i, visited bitor (1 << i)); 46 | if (result and result != INT_MAX) 47 | memo[current][visited] = min(result + graph[current][i], memo[current][visited]); 48 | } 49 | } 50 | return memo[current][visited]; 51 | ``` 52 | 53 | ## 성능 요약 54 | 55 | 메모리: 6116 KB, 시간: 28 ms 56 | 57 | 결과 : [맞았습니다!!](http://boj.kr/604c9e78d1184ccf97b0bf5479fec2bd) -------------------------------------------------------------------------------- /seoul_21_minjaekim/BoJ/Gold I/boj2014/boj2014.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main() 7 | { 8 | ios_base::sync_with_stdio(false); 9 | cin.tie(nullptr); 10 | cout.tie(nullptr); 11 | 12 | 13 | int k, n; 14 | cin >> k >> n; 15 | 16 | pair prime_numbers[100]; 17 | for (int i = 0; i < k; ++i) { 18 | cin >> prime_numbers[i].first; 19 | prime_numbers[i].second = 0; 20 | } 21 | int ugly_numbers[100001] = { 1 }; 22 | 23 | for (int i = 1; i < n + 1; ++i) 24 | { 25 | int min_number = numeric_limits::max(); 26 | int min_index[100]; 27 | int min_count = 0; 28 | for (int j = 0; j < k; ++j) 29 | { 30 | int next_number = prime_numbers[j].first * ugly_numbers[prime_numbers[j].second]; 31 | if (next_number < min_number) 32 | { 33 | min_number = prime_numbers[j].first * ugly_numbers[prime_numbers[j].second]; 34 | min_index[0] = j; 35 | min_count = 1; 36 | } 37 | else if (next_number == min_number) 38 | { 39 | min_index[min_count] = j; 40 | ++min_count; 41 | } 42 | } 43 | ugly_numbers[i] = min_number; 44 | for (int j = 0; j < min_count; ++j) 45 | ++prime_numbers[min_index[j]].second; 46 | } 47 | 48 | cout << ugly_numbers[n] << endl; 49 | 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Silver III/boj11140/Baekjoon_11140.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.InputStreamReader; 3 | import java.util.regex.Pattern; 4 | 5 | /** 6 | * 40분 걸렸음. 7 | * 정규표현식 좀 확실하게 알아야할 것 같은데.. 8 | * 로직 구현하고 정규표현식을 사용해야하는 예외 상황까지 20분만에 떠올라서 다 구현했는데 9 | * 정작 정규표현식 쓰는데 너무 헤매서 결국 서칭하고 20분이 걸렸음. 10 | * 문자열 푸는데 정규표현식 제대로 모르면 너무 힘들다.. 11 | * 따로 공부좀 하자. 12 | */ 13 | public class Baekjoon_11140 { 14 | public static void main(String args[]) throws Exception { 15 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 16 | int T = Integer.parseInt(br.readLine()); 17 | 18 | for (int test_case = 1; test_case <= T; test_case++) { 19 | int result = 3; 20 | 21 | String str = br.readLine(); 22 | String REGEXP_PATTERN_STRING = "[a-z]*l[a-z]l[a-z]*"; 23 | for (int i = 1; i <= 3; i++) { 24 | for (int j = 0; j < str.length() - i + 1; j++) { 25 | String temp = str.substring(j, j + i); 26 | /*System.out.println(temp);*/ 27 | 28 | if(temp.equals("o") || (temp.equals("l"))) result = 2; 29 | if(temp.equals("lo") || temp.equals("ol") || temp.equals("ll")) result = 1; 30 | if(Pattern.matches(REGEXP_PATTERN_STRING, temp)) result = 1; 31 | if(temp.equals("lol")) result = 0; 32 | } 33 | } 34 | 35 | System.out.println(result); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Silver I/BoJ 13335/README.md: -------------------------------------------------------------------------------- 1 | # [백준 13335 트럭](https://www.acmicpc.net/problem/13335) 2 | 3 | solved.ac Silver I 4 | 5 | ## 카테고리 6 | 7 | 구현, 자료구조, 시뮬레이션, 큐 8 | 9 | ## 시간복잡도 10 | 11 | 모든 트럭이 다리를 건널 동안 반복문이 돌아가므로 최악의 경우는 트럭 하나씩 다리를 건너는 경우이다. 12 | 반복문 안에서의 로직은 모두 연결리스트(큐)를 활용한 O(1)연산으로 구성되어 있다. 13 | 따라서 시간복잡도는 O(n X w)이다. 14 | 15 | 이때 n의 최대값은 1,000이고, w의 최댓값은 100이므로 최악의 경우 100,000번의 연산이다. 시간제한 1초 안에는 거뜬하다. 16 | 17 | ## 풀이 18 | 19 | 코테 문제를 읽으면 특정 자료구조를 쓰라고 등떠미는 표현이 등장하는 난이도가 쉬운 문제들이 있다. 예를 들어 이 문제의 경우, 20 | 21 | **하나의 차선**으로 된 다리가 하나 있다. 이 다리를 n 개의 트럭이 건너가려고 한다. **트럭의 순서는 바꿀 수 없으며**
22 | **순서대로 다리를 오른쪽에서 왼쪽으로** 건넌다고 하자. 23 | 24 | 물구나무 서서 봐도 이 문제는 다리를 Queue로 구현하는 문제이다(순서, FIFO). 다만 한가지 신경써야하는 점이 있다면 다리 위에 올라간 트럭의 하중을 기억하고 있어야 한다는 점이다. 25 | 26 | 또한 단위 시간을 기준으로 반복문을 수행하며 다리의 길이 w만큼 큐의 사이즈를 유지하기 위하여 무게가 0인 mockTruck을 생성하여 Queue에 넣어주었다. 27 | 28 | ```java 29 | // 다리 초기화 30 | Queue bridge = new LinkedList<>(); 31 | int time = 0, totalWeight = 0; 32 | for (int i = 0; i < w; i++) { 33 | bridge.add(0); //mockTruck으로 채우기 34 | } 35 | 36 | while (!bridge.isEmpty()) { 37 | time++; 38 | totalWeight -= bridge.poll(); 39 | if(!trucks.isEmpty()) { 40 | if (totalWeight + trucks.peek() > L) { 41 | bridge.add(0); // 다리 길이 유지를 위해 mock 넣어주기 42 | } else { 43 | bridge.add(trucks.peek()); 44 | totalWeight += trucks.poll(); 45 | } 46 | } 47 | } 48 | ``` 49 | 50 | ## 결과 51 | 52 | 결과 : [맞았습니다!!](https://www.acmicpc.net/source/63908629) 53 | -------------------------------------------------------------------------------- /seoul_21_minjaekim/BoJ/Silver II/boj1260/README.md: -------------------------------------------------------------------------------- 1 | # [BoJ 1260 DFS와 BFS](https://www.acmicpc.net/problem/1260) 2 | 3 | solved.ac Silver II 4 | 5 | ## 카테고리 6 | 7 | 그래프 이론, 그래프 탐색, 너비 우선 탐색, 깊이 우선 탐색 8 | 9 | ## 시간복잡도 10 | 11 | DFS와 BFS 모두 각 노드와 에지를 한 번씩 방문하므로 시간 복잡도는 O(N + M)이다. 12 | 13 | ## 풀이 14 | 15 | 재귀를 이용한 dfs 구현 16 | 17 | ```python 18 | def dfs(node): 19 | dfs_visited[node] = True 20 | 21 | visited_node = [node] 22 | for path in sorted(graph[node]): 23 | if not dfs_visited[path]: 24 | visited_node += dfs(path) 25 | 26 | return visited_node 27 | ``` 28 | 29 | queue를 이용한 bfs 구현 30 | 31 | ```python 32 | def bfs(start): 33 | bfs_visited[start] = True 34 | que = deque([start]) 35 | 36 | visited_node = [] 37 | while que: 38 | visited_node.append(que.popleft()) 39 | for node in sorted(graph[visited_node[-1]]): 40 | if not bfs_visited[node]: 41 | que.append(node) 42 | bfs_visited[node] = True 43 | 44 | return visited_node 45 | ``` 46 | 47 | dict를 이용한 graph path 핸들링 48 | 49 | ```python 50 | N, M, V = map(int, sys.stdin.readline().split()) 51 | graph = defaultdict(set) 52 | for _ in range(M): 53 | s, e = map(int, sys.stdin.readline().split()) 54 | graph[s].add(e) 55 | graph[e].add(s) 56 | ``` 57 | 58 | list를 이용한 방문 체크 59 | 60 | ```python 61 | dfs_visited = [False] * (N + 1) 62 | bfs_visited = [False] * (N + 1) 63 | ``` 64 | 65 | 실행 및 결과 출력 66 | 67 | ```python 68 | sys.stdout.write(' '.join(map(str, dfs(V))) + "\n" + ' '.join(map(str, bfs(V)))) 69 | ``` 70 | 71 | ## 결과 72 | 73 | 결과 : [맞았습니다!!](http://boj.kr/34fe82abdd904b09bbbf7943d8376185) 74 | -------------------------------------------------------------------------------- /seoul_17_choijunho/BOJ/boj14426.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | #define ll long long 4 | #define fastio ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); 5 | #define loop(k, sz) for(int k = 0; k < sz; k++) 6 | #define endl '\n' 7 | 8 | class Node{ 9 | public: 10 | char alphabet; 11 | Node* next[26]; 12 | }; 13 | int N, M; 14 | vector wordlist; 15 | vector checklist; 16 | int main() { 17 | fastio 18 | cin >> N >> M; 19 | loop(n, N){ 20 | string tmp; 21 | cin >> tmp; 22 | wordlist.push_back(tmp); 23 | } 24 | loop(m, M){ 25 | string tmp; 26 | cin >> tmp; 27 | checklist.push_back(tmp); 28 | } 29 | Node* headnode = new Node(); 30 | loop(n, N){ 31 | string str = wordlist[n]; 32 | Node* currNode = headnode; 33 | loop(m, str.length()){ 34 | char currc = str[m]; 35 | int num = currc - 'a'; 36 | if(currNode->next[num] == NULL) currNode->next[num] = new Node(); 37 | currNode = currNode->next[num]; 38 | } 39 | } 40 | int includeString = 0; 41 | loop(n, M){ 42 | string str = checklist[n]; 43 | Node* currNode = headnode; 44 | bool existCheck = true; 45 | loop(m, str.length()){ 46 | char currc = str[m]; 47 | int num = currc - 'a'; 48 | if(currNode->next[num] == NULL) { 49 | existCheck = false; 50 | break; 51 | } 52 | currNode = currNode->next[num]; 53 | } 54 | if(existCheck) includeString++; 55 | } 56 | cout << includeString << endl; 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Silver I/BoJ 9465/README.md: -------------------------------------------------------------------------------- 1 | # [백준 9465 스티커](https://www.acmicpc.net/problem/9465) 2 | 3 | solved.ac Silver I 4 | 5 | ## 카테고리 6 | 7 | DP 8 | 9 | ## 시간복잡도 10 | 11 | DP를 이용한 풀이에서 O(n)이 걸린다. 12 | 제한시간이 1초이고 배열이 최대 n열을 가진다. 13 | 이때 n은 최대 100,000이므로 O(n) 또는 O(nlogn)연산이 필요하다. <- O(n ^ 2)은 무조건 터진다. 14 | 15 | ## 풀이 16 | 17 | 너무 당연한 말이지만 DP 문제를 접근할 때 가장 중요한 것은 특정 범위까지의 값을 구하기 위해서 다른 범위까지의 값을 이용하여 효율적으로 결과를 도출하는 것이다. 18 | 19 | 이 문제는 아래와 같이 접근했다. 20 | 21 | 이차원 배열 map[2][n]을 선언했다고 가정하고 3개의 스티커를 떼어보자. 22 | 23 | 우선 (0,0)에 존재하는 스티커를 뜯는다고 생각해보자. 그럼 상황은 아래와 같이 변한다. 24 | |1|2|3|4|5| 25 | |:------:|:---:|:---:|:---:|:---:| 26 | |O|X|-|-|-| 27 | |X|-|-|-|-| 28 | 29 | 이제 (2,1)의 스티커를 뜯을 수 있다. 30 | |1|2|3|4|5| 31 | |:------:|:---:|:---:|:---:|:---:| 32 | |O|X|-|-|-| 33 | |X|O|X|-|-| 34 | 35 | 세번째 스티커는 (3,0)에서 찢을 것이다. 36 | |1|2|3|4|5| 37 | |:------:|:---:|:---:|:---:|:---:| 38 | |O|X|O|X|-| 39 | |X|O|X|-|-| 40 | 41 | 여기서 잠시 멈추고 생각해 보아야한다.
세개의 스티커를 찢은 지금 점수가 가장 높다고 확신할 수 있는가? *아니다* 42 | 43 | |1|2|3|4|5| 44 | |:------:|:---:|:---:|:---:|:---:| 45 | |O|X|O|X|-| 46 | |X|O|X|-|-| 47 | 48 | |1|2|3|4|5| 49 | |:------:|:---:|:---:|:---:|:---:| 50 | |X|X|O|X|-| 51 | |O|X|X|-|-| 52 | 53 | 우리는 빨간 동그라미를 선택했을 때의 점수 최댓값을 알기 위해 노란색 원 두 가지 경우의 수 중에 점수가 더 높은 것을 선택해야 한다. 54 | 이를 알고리즘으로 활용하기 위해 수식으로 바꾸어야 한다. 55 | 56 | ```java 57 | dp[0][i] = Math.max(dp[1][i - 2], dp[1][i - 1]) + map[0][i]; 58 | ``` 59 | 60 | 모든 연산이 끝나서 1행과 2행 끝에 두가지 최댓값이 나오면 그 둘 중 더 큰 값을 결과값으로 제출한다. 61 | 62 | ## 결과 63 | 64 | 결과 : [맞았습니다!!](https://www.acmicpc.net/source/63644597) 65 | -------------------------------------------------------------------------------- /gumi_4_wonjulee/boj/boj1244/boj1244.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.StringTokenizer; 5 | 6 | public class Main { 7 | 8 | public static int[] arr; 9 | public static void main(String[] args) throws IOException { 10 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 11 | StringTokenizer st = new StringTokenizer(br.readLine()); 12 | 13 | int n = Integer.parseInt(st.nextToken()); 14 | arr = new int[n]; 15 | 16 | st = new StringTokenizer(br.readLine()); 17 | for(int i=0; i= arr.length || data-i < 0) { 59 | break; 60 | } 61 | if(arr[data+i] == arr[data-i]) { 62 | arr[data+i] ^= 1; 63 | arr[data-i] ^= 1; 64 | } else { 65 | return arr; 66 | } 67 | } 68 | return arr; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /seoul_21_minjaekim/MinCoding/Algorithm Tower/Dijkstra Tower/6/min_dijkstra_tower_6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define MAX_SIZE 1000 6 | 7 | using namespace std; 8 | 9 | int map[MAX_SIZE][MAX_SIZE]; 10 | bool visited[MAX_SIZE][MAX_SIZE]; 11 | pair directions[4] = { {0, 1}, {1, 0}, {0, -1}, {-1, 0} }; 12 | 13 | int dijkstra(pair start = { 0, 0 }, int map_size = MAX_SIZE) { 14 | priority_queue>, vector>>, greater<>> pq; 15 | pq.emplace(map[start.second][start.first], start); 16 | visited[start.second][start.first] = true; 17 | int max_dist = 0; 18 | 19 | while (!pq.empty()) { 20 | auto [cost, pos] = pq.top(); 21 | auto [cur_x, cur_y] = pos; 22 | pq.pop(); 23 | 24 | for (auto [dx, dy] : directions) { 25 | int next_x = cur_x + dx; 26 | int next_y = cur_y + dy; 27 | 28 | if (next_x < 0 || next_x >= map_size || next_y < 0 || next_y >= map_size || map[next_y][next_x] == -1) continue; 29 | 30 | if (!visited[next_y][next_x]) { 31 | int next_cost = cost + map[next_y][next_x]; 32 | max_dist = max(max_dist, next_cost); 33 | visited[next_y][next_x] = true; 34 | pq.emplace(next_cost, make_pair(next_x, next_y)); 35 | } 36 | } 37 | } 38 | 39 | return max_dist; 40 | } 41 | 42 | int main() 43 | { 44 | ios_base::sync_with_stdio(false); 45 | cin.tie(nullptr); 46 | cout.tie(nullptr); 47 | 48 | int y, x, n; 49 | cin >> y >> x >> n; 50 | for (int i = 0; i < n; ++i) { 51 | for (int j = 0; j < n; ++j) { 52 | cin >> map[i][j]; 53 | } 54 | } 55 | 56 | cout << dijkstra({ x, y }, n) << '\n'; 57 | 58 | return 0; 59 | } -------------------------------------------------------------------------------- /seoul_21_minjaekim/SWEA/D2/swea12712/README.md: -------------------------------------------------------------------------------- 1 | # [[D2] 파리퇴치3 - 12712](https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AXuARWAqDkQDFARa) 2 | 3 | ## 카테고리 4 | 5 | 브루트포스 6 | 7 | ## 시간복잡도 8 | 9 | O(N^2 * M) 10 | 11 | ## 풀이 12 | 13 | 그리드 필드 입력을 받아 vector 컨테이너를 초기화 한다. 14 | 15 | ```cpp 16 | int N, M, result = 0; 17 | cin >> N >> M; 18 | vector> field(N, vector(N)); 19 | 20 | for (auto& row : field) 21 | for (int& fly : row) 22 | cin >> fly; 23 | ``` 24 | 25 | 스프레이의 패턴을 델타 배열로 선언한다. 26 | 27 | ```cpp 28 | int dx_plus[] = {1, -1, 0, 0}; 29 | int dy_plus[] = {0, 0, 1, -1}; 30 | int dx_x[] = {1, 1, -1, -1}; 31 | int dy_x[] = {1, -1, 1, -1}; 32 | ``` 33 | 34 | 필드를 순회하며 스프레이 패턴의 합을 구하고 그 중 최대값을 저장한다. 35 | 36 | ```cpp 37 | for (int i = 0; i < N; i++) { 38 | for (int j = 0; j < N; j++) { 39 | int sum = field[i][j]; 40 | for (int k = 0; k < 4; k++) { 41 | for (int l = 1; l < M; l++) { 42 | int x = i + dx_plus[k] * l; 43 | int y = j + dy_plus[k] * l; 44 | if (x < 0 or N <= x or y < 0 or N <= y) 45 | break; 46 | sum += field[x][y]; 47 | } 48 | } 49 | result = max(result, sum); 50 | sum = field[i][j]; 51 | for (int k = 0; k < 4; k++) { 52 | for (int l = 1; l < M; l++) { 53 | int x = i + dx_x[k] * l; 54 | int y = j + dy_x[k] * l; 55 | if (x < 0 or N <= x or y < 0 or N <= y) 56 | break; 57 | sum += field[x][y]; 58 | } 59 | } 60 | result = max(result, sum); 61 | } 62 | } 63 | ``` 64 | 65 | 결과를 출력한다. 66 | 67 | ```cpp 68 | cout << '#' << test_case << ' ' << result << '\n'; 69 | ``` 70 | 71 | ## 성능 요약 72 | 73 | 메모리: 4,256 KB, 시간: 6 ms, 코드길이: 1,707 Bytes 74 | -------------------------------------------------------------------------------- /seoul_21_minjaekim/BoJ/Gold IV/boj2602/README.md: -------------------------------------------------------------------------------- 1 | # [BoJ 2602 돌다리 건너기](https://www.acmicpc.net/problem/2602) 2 | 3 | solved.ac Gold IV 4 | 5 | ## 카테고리 6 | 7 | 다이나믹 프로그래밍 8 | 9 | ## 시간복잡도 10 | 11 | 두루마리길이를 N, 다리길이를 M이라고 할 때, O(N*M)이다. 12 | 13 | ## 해설 14 | 15 | 각 다리를 건너는 방법의 수를 추적하기 위한 3차원 DP 배열이다. 16 | 17 | [2]는 어느 다리부터 시작하는지에 따른 2가지 경우를 나눠서 저장하기 위한 배열이다. 18 | 19 | [20]은 두루마리에 적힌 문자열의 몇번째 문자를 읽고 있는지에 따른 20가지 경우를 나눠서 저장하기 위한 배열이다. 20 | 21 | [100]은 두루마리에 적힌 문자열과 같은 문자의 발판이 몇개가 있는지 누적하여 저장하기 위한 배열이다. 22 | 23 | ```cpp 24 | int dp[2][20][100] = {0,}; 25 | ``` 26 | 27 | 첫번째 발판을 악마다리부터 시작했다면, 두번째 발판은 천사다리, 세번째 발판은 악마다리가 되어야 한다. 28 | 어느 다리부터 시작했는지와, 몇 번째 발판인지를 이용해 어느 다리를 밟아야 하는지 계산해준다. 29 | 30 | ```cpp 31 | int devil_or_angel = (i + j) % 2; 32 | ``` 33 | 34 | 첫 발판은 누적시켜나갈 기존 발판과 비교할 필요가 없으므로, 따로 처리해준다. 35 | 36 | ```cpp 37 | if (j == 0) 38 | dp[i][0][0] = (target[0] == bridge[devil_or_angel][0]); 39 | ``` 40 | 41 | 두루마리의 순서에 맞게 j번째의 두루마리 발판을 밟을 수 있는 경우의 수는, j - 1번째의 두루마리 발판을 밟을 수 있는 경우의 수를 누적시킨다. 42 | 43 | 예를 들어 두루마리가 `ABC`이고, 악마의 다리가 `AAACC`, 천사의 다리가 `BBBBB`일 때, 악마의 다리부터 시작했다면 다음과 같이 계산될 수 있다. 44 | 45 | | 악마 | A | A | A | C | C | 46 | | :-: |:-:|:-:|:-:|:-:|:-:| 47 | | 천사 | B | B | B | B | B | 48 | |A(악마)| 1 | 2 | 3 | 0 | 0 | 49 | |B(천사)| 0 | 1 | 3 | 6 | 0 | 50 | |C(악마)| 0 | 0 | 0 | 3 | 9 | 51 | 52 | 위의 표와 같이 두루마리와 같이 발판을 밟을 수 있는 경우의 수를 누적시켜나가면, 마지막 발판을 밟을 수 있는 경우의 수를 구할 수 있다. 53 | 54 | ```cpp 55 | for (int k = 1; k < int(bridge[i].size() - target.size()) + j + 1; ++k) { 56 | if (target[j] == bridge[devil_or_angel][k]) { 57 | if (j == 0) 58 | dp[i][j][k] = dp[i][j][k - 1] + 1; 59 | else 60 | dp[i][j][k] = dp[i][j][k - 1] + dp[i][j - 1][k - 1]; 61 | } 62 | else { 63 | dp[i][j][k] = dp[i][j][k - 1]; 64 | } 65 | } 66 | ``` 67 | 68 | ## 성능 요약 69 | 70 | 메모리: 2024 KB, 시간: 0 ms 71 | 72 | 결과 : [맞았습니다!!](http://boj.kr/a04571028f124340a045f3ccd400eaa5) -------------------------------------------------------------------------------- /gumi_4_wonjulee/boj/boj2493/boj2493.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | import java.io.*; 3 | 4 | // 스택이 비어있으면 push 5 | // 현재 값과 스택의 마지막값을 비교 -> 현재값이 더 클 경우 스택값 pop&현재 인덱스i 출력, 현재값push 6 | // -> 현재값이 더 작을 경우 push만 7 | // -> i가 끝났는데 !isEmpty()일 경우 0 으로 채우기 8 | 9 | public class Main { 10 | public static void main(String[] args) throws IOException { 11 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 12 | StringBuilder sb = new StringBuilder(); 13 | int N = Integer.parseInt(br.readLine()); 14 | Integer[] arr = new Integer[N]; 15 | Deque stack = new ArrayDeque<>(); 16 | List list = new LinkedList<>(); 17 | 18 | StringTokenizer st = new StringTokenizer(br.readLine()); 19 | 20 | // 1. 탑 입력받기 21 | for(int i=0; i=0; i--) { 27 | 28 | // 3. 스택이 비어있으면 push(addFirst) 29 | if(stack.isEmpty()) { 30 | stack.addFirst(arr[i]); 31 | } else { 32 | // 4. 현재 원소가 스택의 top보다 클 때: pop & list에 수신받은 탑 인덱스 add & 현재 원소 push 33 | if(stack.peek() < arr[i]) { 34 | while(!stack.isEmpty() && stack.peek() < arr[i]) { // 현재 원소보다 작은 값인 스택 요소를 전부 pop&list.add 35 | stack.poll(); 36 | list.add(i+1); 37 | } 38 | stack.addFirst(arr[i]); 39 | 40 | // 5. 현재 원소가 스택의 top보다 작을 때: 스택에 push 41 | } else if(stack.peek() >= arr[i]) { 42 | stack.addFirst(arr[i]); 43 | } 44 | } 45 | } 46 | 47 | // 배열을 한바퀴 다 돌고도 스택에 남아있는 탑들 (자기자신보다 높은 탑을 발견하지 못해 수신받지 못한 탑들) 48 | while(!stack.isEmpty()) { 49 | int idx = Arrays.asList(arr).indexOf(stack.pollLast()); 50 | list.add(arr.length-idx-1, 0); // 해당 원소 인덱스에 0 삽입 51 | } 52 | 53 | 54 | // 답 출력 55 | Collections.reverse(list); 56 | for(Integer i:list ) { 57 | sb.append(i).append(" "); 58 | } 59 | 60 | sb.deleteCharAt(sb.length() - 1); // 마지막 공백 제거 61 | System.out.println(sb); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /seoul_21_minjaekim/SWEA/D2/swea12712/swea12712.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main() { 7 | ios_base::sync_with_stdio(false); 8 | cin.tie(nullptr); 9 | cout.tie(nullptr); 10 | 11 | int T; 12 | cin >> T; 13 | for (int test_case = 1; test_case <= T; ++test_case) 14 | { 15 | int N, M, result = 0; 16 | cin >> N >> M; 17 | vector> field(N, vector(N)); 18 | 19 | for (auto& row : field) 20 | for (int& fly : row) 21 | cin >> fly; 22 | 23 | int dx_plus[] = {1, -1, 0, 0}; 24 | int dy_plus[] = {0, 0, 1, -1}; 25 | int dx_x[] = {1, 1, -1, -1}; 26 | int dy_x[] = {1, -1, 1, -1}; 27 | 28 | for (int i = 0; i < N; i++) { 29 | for (int j = 0; j < N; j++) { 30 | int sum = field[i][j]; 31 | for (int k = 0; k < 4; k++) { 32 | for (int l = 1; l < M; l++) { 33 | int x = i + dx_plus[k] * l; 34 | int y = j + dy_plus[k] * l; 35 | if (x < 0 or N <= x or y < 0 or N <= y) 36 | break; 37 | sum += field[x][y]; 38 | } 39 | } 40 | result = max(result, sum); 41 | sum = field[i][j]; 42 | for (int k = 0; k < 4; k++) { 43 | for (int l = 1; l < M; l++) { 44 | int x = i + dx_x[k] * l; 45 | int y = j + dy_x[k] * l; 46 | if (x < 0 or N <= x or y < 0 or N <= y) 47 | break; 48 | sum += field[x][y]; 49 | } 50 | } 51 | result = max(result, sum); 52 | } 53 | } 54 | 55 | cout << '#' << test_case << ' ' << result << '\n'; 56 | } 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Silver I/BoJ 13335/Baekjoon_13335.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.LinkedList; 5 | import java.util.Queue; 6 | import java.util.StringTokenizer; 7 | 8 | /** 9 | * 50분 소요 10 | * 데이터가 밀려 나가야하는 자료구조 특성을 이용하여 Queue를 구현한건 당연했는데 11 | * Queue를 채우고 구현하는 것과 Queue를 비우고 구현하는 것에서 차이점이 나타났다. 12 | * 전자로 시작했다면 훨씬 시간 단축하였겠지만 후자로 시작하다 문제점을 깨닫고 전자로 돌아가느라 시간이 많이 잡아 먹혔다. 13 | * 문제 특성을 잘 기억해두고 앞으로 같은 경우의 Queue 구현을 만난다면 참고하도록 하자. 14 | */ 15 | 16 | public class Baekjoon_13335 { 17 | 18 | public static void main(String[] args) throws IOException { 19 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 20 | StringTokenizer st = new StringTokenizer(br.readLine()); 21 | 22 | int n = Integer.parseInt(st.nextToken()); // n은 다리를 건너는 트럭의 수, 23 | int w = Integer.parseInt(st.nextToken()); // w는 다리의 길이, 24 | int L = Integer.parseInt(st.nextToken()); // 그리고 L은 다리의 최대하중 25 | 26 | Queue trucks = new LinkedList<>(); 27 | st = new StringTokenizer(br.readLine()); 28 | for (int i = 0; i < n; i++) { 29 | trucks.add(Integer.parseInt(st.nextToken())); 30 | } 31 | 32 | Queue bridge = new LinkedList<>(); 33 | int time = 0, totalWeight = 0; 34 | for (int i = 0; i < w; i++) { 35 | bridge.add(0); 36 | } 37 | 38 | //int round =0; 39 | while (!bridge.isEmpty()) { 40 | //System.out.println("#" + round++ + " : " + bridge); 41 | time++; 42 | totalWeight -= bridge.poll(); 43 | if(!trucks.isEmpty()) { 44 | if (totalWeight + trucks.peek() > L) { 45 | bridge.add(0); 46 | } else { 47 | bridge.add(trucks.peek()); 48 | totalWeight += trucks.poll(); 49 | } 50 | } 51 | } 52 | 53 | System.out.println(time); 54 | } 55 | } -------------------------------------------------------------------------------- /seoul_21_minjaekim/Softeer/HSAT_7th/2/HSAT_7th_2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | struct Pos { 6 | int row, col; 7 | }; 8 | 9 | struct Directions { 10 | int drow, dcol; 11 | }; 12 | 13 | Directions direc[4] = { 14 | {-1, 0}, 15 | {0, -1}, 16 | {1, 0}, 17 | {0, 1} 18 | }; 19 | 20 | bool visited[4][4]; 21 | int pos_map[4][4]; 22 | 23 | int dfs(int n, int end_idx, Pos cur_pos, int pos_idx = 2) { 24 | int cur_idx = pos_map[cur_pos.row][cur_pos.col]; 25 | if (cur_idx == end_idx && cur_idx == pos_idx) 26 | return 1; 27 | else if (cur_idx == pos_idx) 28 | ++pos_idx; 29 | else if (cur_idx) 30 | return 0; 31 | 32 | int count = 0; 33 | for (auto d : direc) { 34 | Pos next_pos; 35 | next_pos.row = cur_pos.row + d.drow; 36 | next_pos.col = cur_pos.col + d.dcol; 37 | 38 | if (next_pos.row < 0 || next_pos.row >= n || next_pos.col < 0 || next_pos.col >= n || visited[next_pos.row][next_pos.col]) 39 | continue; 40 | 41 | visited[next_pos.row][next_pos.col] = true; 42 | count += dfs(n, end_idx, next_pos, pos_idx); 43 | visited[next_pos.row][next_pos.col] = false; 44 | } 45 | return count; 46 | } 47 | 48 | int main(int argc, char** argv) 49 | { 50 | ios_base::sync_with_stdio(false); 51 | cin.tie(nullptr); 52 | cout.tie(nullptr); 53 | 54 | int n, m; 55 | cin >> n >> m; 56 | 57 | for (int i = 0; i < n; ++i) 58 | for (int j = 0; j < n; ++j) 59 | cin >> visited[i][j]; 60 | 61 | int row, col; 62 | Pos start_pos; 63 | cin >> row >> col; 64 | visited[row - 1][col - 1] = true; 65 | start_pos.row = row - 1; 66 | start_pos.col = col - 1; 67 | 68 | for (int i = 2; i <= m; ++i) { 69 | Pos pos; 70 | cin >> row >> col; 71 | pos_map[row - 1][col - 1] = i; 72 | pos.row = row - 1; 73 | pos.col = col - 1; 74 | } 75 | 76 | cout << dfs(n, m, start_pos) << '\n'; 77 | 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /seoul_x_hwijoonchoi/BOJ/boj2194/boj2194.py: -------------------------------------------------------------------------------- 1 | # 2194 유닛 이동시키기 8:20 2 | ''' 3 | 최소 이동 횟수 -> bfs 고려 4 | 5 | 1. 유닛을 graph에서 어떤식으로 표현할지? 6 | 2. 장애물과의 충돌을 어떻게 판단할지? 7 | 3. 유닛의 이동을 어떻게 처리할지? 8 | 4. 유닛의 도착을 어떻게 처리할지? 9 | 10 | unit 11 | unit의 크기에 맞게 순찰을 돌면서 12 | 장애물과 부딪히는지를 판단하면 될 듯? 13 | 14 | ''' 15 | 16 | from collections import deque 17 | 18 | def Unit_check(x,y): 19 | ''' 20 | unit이 graph밖으로 나가면 False 21 | unit이 장애물을 만나면 False 22 | 그 외 : True 23 | ''' 24 | for i in range(x,x+a): 25 | for j in range(y,y+b): 26 | if i < 0 or i > (n-1) or j < 0 or j > (m-1): # graph 밖으로 나가면 27 | return False 28 | if graph[i][j] == -1: # 장애물을 만나면 29 | return False 30 | 31 | return True # 그 외 True return 32 | 33 | 34 | def Bfs(): 35 | deq = deque() 36 | deq.append(start) # 시작점 넣기 37 | dx = [0,0,-1,1] # 상하좌우 설정 38 | dy = [1,-1,0,0] 39 | 40 | while deq: 41 | x,y = deq.popleft() 42 | if [x,y] == end: # 도착점에 도착하면 최소 회수 출력 43 | print(graph[x][y]) 44 | return 45 | for i in range(4): 46 | nx = x + dx[i] 47 | ny = y + dy[i] 48 | if nx < 0 or nx > (n-1) or ny < 0 or ny > (m-1): 49 | continue 50 | if graph[nx][ny] != 0: 51 | continue 52 | if Unit_check(nx,ny): 53 | graph[nx][ny] = graph[x][y] + 1 54 | deq.append([nx,ny]) 55 | 56 | 57 | print(-1) 58 | return 59 | 60 | 61 | # 1. 입력 받기 62 | # n: graph세로(행,x), m: graph가로(열,y), a: unit세로(행), b: unit가로(열), k: 장애물 개수 63 | n, m, a, b, k = map(int,input().split()) 64 | 65 | # graph 만들기 66 | graph = [[0 for j in range(m)] for i in range(n)] 67 | 68 | # 장애물 표시 69 | for i in range(k): 70 | x,y = map(int,input().split()) 71 | graph[x-1][y-1] = -1 72 | 73 | # 시작점, 끝점 74 | start = list(map(int,input().split())) 75 | start[0] -= 1 76 | start[1] -= 1 77 | end = list(map(int,input().split())) 78 | end[0] -= 1 79 | end[1] -= 1 80 | 81 | Bfs() -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Gold II/Boj 1167/Boj1167.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.ArrayList; 5 | import java.util.StringTokenizer; 6 | 7 | 8 | public class Boj1167 { 9 | 10 | static int V; 11 | static ArrayList> graph = new ArrayList<>(); 12 | static boolean[] visit; 13 | static int max = Integer.MIN_VALUE; 14 | static int endPoint; 15 | 16 | public static void main(String[] args) throws IOException { 17 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 18 | StringBuilder sb = new StringBuilder(); 19 | StringTokenizer st; 20 | 21 | int V = Integer.parseInt(br.readLine()); 22 | for(int i = 0; i <= V; i++) { 23 | graph.add(new ArrayList<>()); 24 | } 25 | visit = new boolean[V + 1]; 26 | 27 | int u, v, cost; 28 | for(int i = 0; i < V; i++) { 29 | st = new StringTokenizer(br.readLine()); 30 | 31 | u = Integer.parseInt(st.nextToken()); 32 | while(true) { 33 | v = Integer.parseInt(st.nextToken()); 34 | if(v == -1) break; 35 | 36 | cost = Integer.parseInt(st.nextToken()); 37 | 38 | graph.get(u).add(new int[] {v, cost}); 39 | } 40 | } 41 | 42 | dfs(1, 0); 43 | 44 | max = Integer.MIN_VALUE; 45 | visit = new boolean[V + 1]; 46 | dfs(endPoint, 0); 47 | 48 | System.out.println(max); 49 | } 50 | 51 | static void dfs(int now, int dist) { 52 | if(visit[now]) return; 53 | 54 | visit[now] = true; 55 | 56 | for(int i = 0; i < graph.get(now).size(); i++) { 57 | if(!visit[graph.get(now).get(i)[0]]) { 58 | dfs(graph.get(now).get(i)[0], dist + graph.get(now).get(i)[1]); 59 | } 60 | } 61 | 62 | if(max < dist) { 63 | max = dist; 64 | endPoint = now; 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Gold V/Boj 15591/Boj15591.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.ArrayList; 5 | import java.util.LinkedList; 6 | import java.util.Queue; 7 | import java.util.StringTokenizer; 8 | 9 | public class Main { 10 | 11 | public static void main(String[] args) throws IOException { 12 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 13 | StringTokenizer st = new StringTokenizer(br.readLine()); 14 | 15 | int N = Integer.parseInt(st.nextToken()); 16 | int Q = Integer.parseInt(st.nextToken()); 17 | ArrayList> graph = new ArrayList<>(); 18 | for(int i = 0; i <= N; i++) { 19 | graph.add(new ArrayList<>()); 20 | } 21 | 22 | int a, b, weight; 23 | for(int i = 0 ; i < N - 1;i++) { 24 | st = new StringTokenizer(br.readLine()); 25 | a = Integer.parseInt(st.nextToken()); 26 | b = Integer.parseInt(st.nextToken()); 27 | weight = Integer.parseInt(st.nextToken()); 28 | 29 | graph.get(a).add(new int[] {b, weight}); 30 | graph.get(b).add(new int[] {a, weight}); 31 | } 32 | 33 | int[][] usadoMap = new int[N + 1][N + 1]; 34 | for(int i = 0; i < Q; i++) { 35 | 36 | } 37 | 38 | StringBuilder sb = new StringBuilder(); 39 | while(Q-- > 0) { 40 | st = new StringTokenizer(br.readLine()); 41 | int k = Integer.parseInt(st.nextToken()); 42 | int v = Integer.parseInt(st.nextToken()); 43 | 44 | // 다음 영상과의 유사도(USADO)가 K보다 작은 경우 다음 영상은 추천되지 않는다고 생각 45 | int result = 0; 46 | 47 | boolean[] visit = new boolean[N + 1]; 48 | Queue q = new LinkedList<>(); 49 | q.add(v); 50 | visit[v] = true; 51 | 52 | while(!q.isEmpty()) { 53 | int now = q.poll(); 54 | 55 | for(int[] edge : graph.get(now)) { 56 | if(!visit[edge[0]] && edge[1] >= k) { 57 | q.add(edge[0]); 58 | visit[edge[0]] = true; 59 | result++; 60 | } 61 | } 62 | } 63 | 64 | sb.append(result).append("\n"); 65 | } 66 | 67 | System.out.println(sb); 68 | } 69 | } -------------------------------------------------------------------------------- /seoul_21_minjaekim/Softeer/HSAT_7th/1/README.md: -------------------------------------------------------------------------------- 1 | # [7차 Softeer 정기 역량 진단] 1번 - 자동차 테스트 2 | 3 | ## 카테고리 4 | 5 | 자료구조, 해시 테이블 6 | 7 | ## 시간복잡도 8 | 9 | `O(N * log N + Q)` 10 | 11 | ## 문제 12 | 13 | 자동차의 연비들을 제공해준다. 14 | 15 | 자동차 중 임의의 3개를 골랐을 때, 중앙값이 `m`이 될 수 있는 서로 다른 경우의 수를 구하라. 16 | 17 | n대의 자동차에 대한 연비의 정보와 `q`개의 `m`값이 주어진다. 18 | 19 | ## 제약 조건 20 | 21 | - 1 ≤ n ≤ 50,000 22 | - 1 ≤ q ≤ 200,000 23 | - 1 ≤ 연비 ≤ 1,000,000,000 24 | - 1 ≤ m ≤ 1,000,000,000 25 | - 각 차량의 연비는 모두 다르다. 26 | 27 | ## 시간 제약 28 | 29 | - Java : 3초 30 | - C++ : 2초 31 | - Python : 2초 32 | 33 | ## 입력 형식 34 | 35 | - 첫 번째 줄에 `n`, `q`가 주어진다. 36 | - 두 번째 줄에 `n`개의 자동차의 연비에 해당하는 값이 공백을 사이에 두고 주어진다. 37 | - 세 번째 줄부터 `q`개의 줄에 걸쳐 각 줄에 `m`값이 주어진다. 38 | 39 | ## 출력 형식 40 | 41 | `q`개의 줄에 걸쳐 각 줄에 `m`값이 중앙값이 될 수 있는 서로 다른 경우의 수를 출력한다. 42 | 43 | ## 해설 44 | 45 | 데이터를 입력받는다. `O(N)` 46 | 47 | ```cpp 48 | int n, q; 49 | cin >> n >> q; 50 | 51 | int cars[50000]; 52 | for (int i = 0; i < n; ++i) 53 | cin >> cars[i]; 54 | ``` 55 | 56 | 입력받은 데이터를 정렬한다. `O(N * log N)` 57 | 58 | ```cpp 59 | sort(cars, cars + n); 60 | ``` 61 | 62 | 정렬된 데이터를 키로, 인덱스를 값으로 하는 해시 테이블을 만든다. 이때 해시 테이블에 없는 값을 조회했을때 나오는 리턴값인 `0`과 구분을 위해 인덱스에 `1`을 더해서 저장한다. `O(N)` 63 | 64 | ```cpp 65 | unordered_map map; 66 | for (int i = 0; i < n; ++i) 67 | map[cars[i]] = i + 1; 68 | ``` 69 | 70 | `q`개의 `m`값을 입력받아 해시 테이블에서 조회한다. 3개의 값을 뽑았을 때, `m`이 중간값이 되는 경우는 `m`의 왼쪽에서 한 개, `m`의 오른쪽에서 한 개를 뽑는 경우의 수와 같다. 이는 `m`의 왼쪽 개수 * `m`의 오른쪽 개수로 상수시간으로 계산이 가능하다. `O(Q)` 71 | 72 | ```cpp 73 | for (int i = 0; i < q; ++i) { 74 | int m, m_idx; 75 | cin >> m; 76 | m_idx = map[m]; 77 | cout << (m_idx ? (m_idx - 1) * (n - m_idx) : m_idx) << '\n'; 78 | } 79 | ``` 80 | 81 | ## 문제 분석 82 | 83 | 문제의 제약조건에서 알 수 있다싶이, `n`의 최대값이 `50,000`이고 `q`의 최대값이 `200,000`이다. `n`이 `50,000`이고 `q`가 `200,000`이라면, `n`개의 자동차 중 임의의 3개를 직접 골라서, 중앙값이 `m`이 될 수 있는 서로 다른 경우의 수를 구하는 것은 `O(N^3)`의 시간복잡도를 가진다. 제한시간인 `2초`를 넘어가기 때문에, `O(N^3)`의 알고리즘으로는 풀 수 없다. 84 | 85 | 이는 최소한 `O(Q * log N)`의 알고리즘으로 풀어야 한다는 것을 의미한다. 86 | 87 | `O(Q * log N)`의 알고리즘으로 풀기 위해서는, `n`개의 자동차의 연비를 정렬한 다음 각 `q`에 대해 `m`의 인덱스를 이진 탐색으로 찾아야 한다. 88 | 89 | 본 풀이와 같이 해시 테이블을 이용한 `O(N * log N + Q)` 알고리즘으로도 풀 수 있다. 90 | -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Silver II/BoJ 6884/Baekjoon_6884.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.StringTokenizer; 5 | 6 | public class Baekjoon_6884 { 7 | 8 | public static void main(String[] args) throws IOException { 9 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 10 | StringBuilder sb = new StringBuilder(); 11 | 12 | int t = Integer.parseInt(br.readLine()); 13 | for(int test_case = 1; test_case <= t;test_case++) { 14 | 15 | StringTokenizer st = new StringTokenizer(br.readLine()); 16 | int len = Integer.parseInt(st.nextToken()); 17 | int[] sum = new int[len + 1]; 18 | 19 | for (int i = 1; i <= len; i++) { 20 | sum[i] += sum[i - 1] + Integer.parseInt(st.nextToken()); 21 | } 22 | 23 | int curLen; 24 | int temp; // 누적합 25 | boolean changeFlag = false; 26 | 27 | a: 28 | for (curLen = 2; curLen <= len; curLen++) { 29 | for (int start = 1; start + curLen - 1 <= len; start++) { 30 | temp = sum[start + curLen - 1] - sum[start - 1]; 31 | if (isPrime(temp) && temp >= 2) { 32 | sb.append("Shortest primed subsequence is length ").append(curLen).append(": "); 33 | 34 | while (curLen > 0) { 35 | sb.append((sum[start] - sum[start - 1]) + " "); 36 | start++; 37 | curLen--; 38 | } 39 | sb.append('\n'); 40 | changeFlag = true; 41 | break a; 42 | } 43 | } 44 | } 45 | 46 | if (!changeFlag) { 47 | sb.append("This sequence is anti-primed.").append('\n'); 48 | } 49 | } 50 | 51 | System.out.print(sb); 52 | } 53 | 54 | public static boolean isPrime(int n) { 55 | for (int i = 2; i <= (int) Math.sqrt(n); i++) { 56 | if(n % i == 0) 57 | return false; 58 | } 59 | return true; 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /seoul_x_hwijoonchoi/BOJ/boj2194/README.md: -------------------------------------------------------------------------------- 1 | # [BoJ 2194 bfs](https://www.acmicpc.net/problem/2194) 2 | 3 | solved.ac Gold 5 4 | 5 | ## 카테고리 6 | 7 | bfs 8 | 9 | ## 시간복잡도 10 | 11 | O(N^3) 12 | 13 | ## 풀이 14 | 15 | 1. 구현 16 | 2. bfs 17 | 18 | ```python 19 | # 2194 유닛 이동시키기 8:20 20 | ''' 21 | 최소 이동 횟수 -> bfs 고려 22 | 23 | 1. 유닛을 graph에서 어떤식으로 표현할지? 24 | 2. 장애물과의 충돌을 어떻게 판단할지? 25 | 3. 유닛의 이동을 어떻게 처리할지? 26 | 4. 유닛의 도착을 어떻게 처리할지? 27 | 28 | unit 29 | unit의 크기에 맞게 순찰을 돌면서 30 | 장애물과 부딪히는지를 판단하면 될 듯? 31 | 32 | ''' 33 | 34 | from collections import deque 35 | 36 | def Unit_check(x,y): 37 | ''' 38 | unit이 graph밖으로 나가면 False 39 | unit이 장애물을 만나면 False 40 | 그 외 : True 41 | ''' 42 | for i in range(x,x+a): 43 | for j in range(y,y+b): 44 | if i < 0 or i > (n-1) or j < 0 or j > (m-1): # graph 밖으로 나가면 45 | return False 46 | if graph[i][j] == -1: # 장애물을 만나면 47 | return False 48 | 49 | return True # 그 외 True return 50 | 51 | 52 | def Bfs(): 53 | deq = deque() 54 | deq.append(start) # 시작점 넣기 55 | dx = [0,0,-1,1] # 상하좌우 설정 56 | dy = [1,-1,0,0] 57 | 58 | while deq: 59 | x,y = deq.popleft() 60 | if [x,y] == end: # 도착점에 도착하면 최소 회수 출력 61 | print(graph[x][y]) 62 | return 63 | for i in range(4): 64 | nx = x + dx[i] 65 | ny = y + dy[i] 66 | if nx < 0 or nx > (n-1) or ny < 0 or ny > (m-1): 67 | continue 68 | if graph[nx][ny] != 0: 69 | continue 70 | if Unit_check(nx,ny): 71 | graph[nx][ny] = graph[x][y] + 1 72 | deq.append([nx,ny]) 73 | 74 | 75 | print(-1) 76 | return 77 | 78 | 79 | # 1. 입력 받기 80 | # n: graph세로(행,x), m: graph가로(열,y), a: unit세로(행), b: unit가로(열), k: 장애물 개수 81 | n, m, a, b, k = map(int,input().split()) 82 | 83 | # graph 만들기 84 | graph = [[0 for j in range(m)] for i in range(n)] 85 | 86 | # 장애물 표시 87 | for i in range(k): 88 | x,y = map(int,input().split()) 89 | graph[x-1][y-1] = -1 90 | 91 | # 시작점, 끝점 92 | start = list(map(int,input().split())) 93 | start[0] -= 1 94 | start[1] -= 1 95 | end = list(map(int,input().split())) 96 | end[0] -= 1 97 | end[1] -= 1 98 | 99 | Bfs() 100 | ``` 101 | 102 | ## 결과 103 | 104 | 결과 : [맞았습니다] -------------------------------------------------------------------------------- /seoul_21_minjaekim/BoJ/Platinum IV/boj13907/boj13907.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | struct Edge { 10 | int to; 11 | int cost; 12 | Edge(int to, int cost) : to(to), cost(cost) {} 13 | }; 14 | 15 | struct Node { 16 | int id; 17 | int dist; 18 | int edge_count; 19 | Node(int id, int dist, int edge_count) : id(id), dist(dist), edge_count(edge_count) {} 20 | }; 21 | 22 | vector graph[1000]; 23 | int dist[1001][1001]; 24 | 25 | void dijkstra(int s, int e) { 26 | queue que; 27 | que.push(Node(s, 0, 0)); 28 | dist[s][0] = 0; 29 | while (!que.empty()) { 30 | Node node = que.front(); 31 | que.pop(); 32 | if (node.dist > dist[node.id][node.edge_count]) continue; 33 | for (Edge edge : graph[node.id]) { 34 | int next_dist = node.dist + edge.cost; 35 | if (next_dist < dist[edge.to][node.edge_count + 1]) { 36 | dist[edge.to][node.edge_count + 1] = next_dist; 37 | que.push({ edge.to, next_dist, node.edge_count + 1 }); 38 | } 39 | } 40 | } 41 | } 42 | 43 | int main() { 44 | ios::sync_with_stdio(false); 45 | cin.tie(nullptr); 46 | cout.tie(nullptr); 47 | 48 | int n, m, k, a, b; 49 | cin >> n >> m >> k >> a >> b; 50 | for (int i = 1; i <= n; i++) 51 | for (int j = 0; j < n; j++) 52 | dist[i][j] = numeric_limits::max(); 53 | for (int i = 0; i < m; ++i) 54 | { 55 | int f, t, c; 56 | cin >> f >> t >> c; 57 | graph[f].push_back(Edge(t, c)); 58 | graph[t].push_back(Edge(f, c)); 59 | } 60 | 61 | dijkstra(a, b); 62 | 63 | vector> cand; 64 | int min_dist = dist[b][0]; 65 | for (int i = 1; i < n; ++i) { 66 | if (dist[b][i] < min_dist) { 67 | min_dist = dist[b][i]; 68 | cand.emplace_back(dist[b][i], i); 69 | } 70 | } 71 | sort(cand.begin(), cand.end()); 72 | cout << cand[0].first << '\n'; 73 | 74 | for (int i = 0; i < k; ++i) { 75 | int p; 76 | cin >> p; 77 | for (int j = 0; j < cand.size(); ++j) 78 | cand[j].first += p * cand[j].second; 79 | sort(cand.begin(), cand.end()); 80 | vector> new_cand; 81 | new_cand.push_back(cand[0]); 82 | int min_edge_count = cand[0].second; 83 | for (int j = 1; j < cand.size(); ++j) 84 | if (cand[j].second < min_edge_count) 85 | new_cand.push_back(cand[j]); 86 | cand = new_cand; 87 | cout << cand[0].first << '\n'; 88 | } 89 | 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /seoul_21_jongilchoi/mincodding/bfs/13/bfs_top_13.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | struct info 8 | { 9 | int num; 10 | string s; 11 | }; 12 | 13 | 14 | int d(int n) { // 2배로 만들고 숫자가 4자리를 넘어가면 10000으로 나눈 나머지 15 | n = n * 2; 16 | if (n >= 10000) 17 | return n % 10000; 18 | else 19 | return n; 20 | } 21 | 22 | int sub(int n) { 23 | n -= 1; 24 | if (n == -1) 25 | return 9999; 26 | else 27 | return n; 28 | } 29 | 30 | int l(int n) { 31 | int th = n / 1000; 32 | n = n % 1000; 33 | int hundred = n / 100; 34 | n = n % 100; 35 | int ten = n / 10; 36 | n = n % 10; 37 | int one = n / 1; 38 | int rst = hundred * 1000 + ten * 100 + one * 10 + th; 39 | return rst; 40 | } 41 | int r(int n) { 42 | int th = n / 1000; 43 | n = n % 1000; 44 | int hundred = n / 100; 45 | n = n % 100; 46 | int ten = n / 10; 47 | n = n % 10; 48 | int one = n / 1; 49 | int rst = one * 1000 + th * 100 + hundred * 10 + ten; 50 | return rst; 51 | } 52 | 53 | string bfs(int s, int e) { 54 | queue bfs_q; 55 | int dat[10000] = { 0 }; 56 | string rst = ""; 57 | bfs_q.push({ s,rst }); 58 | while (!bfs_q.empty()) { 59 | info I = bfs_q.front(); bfs_q.pop(); 60 | int now = I.num; 61 | string now_s = I.s; 62 | 63 | if (now == e) { 64 | return now_s; 65 | } 66 | 67 | int rst_d = d(now); 68 | if (dat[rst_d] == 0) 69 | { 70 | dat[rst_d] = 1; 71 | now_s += "D"; 72 | bfs_q.push({ rst_d,now_s }); 73 | now_s = now_s.substr(0, now_s.size() - 1); 74 | } 75 | int rst_s = sub(now); 76 | if (dat[rst_s] == 0) { 77 | dat[rst_s] = 1; 78 | now_s += "S"; 79 | bfs_q.push({ rst_s,now_s }); 80 | now_s = now_s.substr(0, now_s.size() - 1); 81 | } 82 | int rst_l = l(now); 83 | if (dat[rst_l] == 0) { 84 | dat[rst_l] = 1; 85 | now_s += "L"; 86 | bfs_q.push({ rst_l,now_s }); 87 | now_s = now_s.substr(0, now_s.size() - 1); 88 | } 89 | int rst_r = r(now); 90 | if (dat[rst_r] == 0) { 91 | dat[rst_r] = 1; 92 | now_s += "R"; 93 | bfs_q.push({ rst_r,now_s }); 94 | now_s = now_s.substr(0, now_s.size() - 1); 95 | } 96 | } 97 | 98 | } 99 | 100 | int main() { 101 | int size; 102 | cin >> size; 103 | 104 | for (int i = 0; i < size; i++) { 105 | int start, end; 106 | cin >> start >> end; 107 | string result = bfs(start, end); 108 | cout << result << endl; 109 | } 110 | } -------------------------------------------------------------------------------- /seoul_x_hwijoonchoi/BOJ/boj16985/boj16985.py: -------------------------------------------------------------------------------- 1 | from itertools import permutations 2 | from collections import deque 3 | from copy import deepcopy 4 | 5 | def Search(): 6 | global cnt 7 | for _ in range(4): 8 | for _ in range(4): 9 | for _ in range(4): 10 | for _ in range(4): 11 | for _ in range(4): 12 | Rotation(4) # 90도 회전 13 | cnt = min(cnt,Bfs(temp_graph)) # bfs로 현재 그래프에서의 최소 횟수 탐색 14 | if cnt == 12: 15 | return 16 | Rotation(3) 17 | Rotation(2) 18 | Rotation(1) 19 | Rotation(0) 20 | return 21 | 22 | def Maaaaaaaaaze(): 23 | for c in permutations(range(5)): 24 | for i in range(5): 25 | temp_graph[i] = graph[c[i]] # 경우의 수 26 | Search() # cnt return 27 | 28 | 29 | # 그래프 90도 회전 30 | def Rotation(n): 31 | temp = [[0 for j in range(5)] for i in range(5)] 32 | for i in range(5): 33 | for j in range(5): 34 | temp[i][j] = temp_graph[n][4-j][i] 35 | temp_graph[n] = temp 36 | return 37 | 38 | # bfs로 최소 횟수 탐색 39 | def Bfs(graph): 40 | if graph[0][0][0] == 0 or graph[4][4][4] == 0: # 시작이나 끝이 막혀있으면 탈출 불가 41 | return 126 42 | deq = deque() 43 | deq.append([0,0,0]) 44 | visit = [[[-1,-1,-1,-1,-1] for j in range(5)] for i in range(5)] 45 | 46 | visit[0][0][0] = 0 # 시작점 47 | dx = [0,0,1,-1,0,0] 48 | dy = [1,-1,0,0,0,0] 49 | dz = [0,0,0,0,1,-1] 50 | 51 | while deq: 52 | z,x,y = deq.popleft() 53 | if z == 4 and x == 4 and y == 4: #출구 도착 54 | return visit[z][x][y] 55 | 56 | if visit[z][x][y] > cnt: # 시간 단축(현재 탐색중인게 현재cnt값 보다 높아지면 중단) 57 | return visit[z][x][y] 58 | 59 | for i in range(6): 60 | nx = x + dx[i] 61 | ny = y + dy[i] 62 | nz = z + dz[i] 63 | 64 | if nx < 0 or nx > 4 or ny < 0 or ny > 4 or nz < 0 or nz > 4: 65 | continue 66 | if graph[nz][nx][ny] == 1 and visit[nz][nx][ny] == -1: 67 | visit[nz][nx][ny] = visit[z][x][y] + 1 68 | deq.append([nz,nx,ny]) 69 | # 출구 도달 못하면 70 | return 126 71 | 72 | # 1. 입력 받기 73 | graph = [[list(map(int,input().split())) for j in range(5)]for i in range(5)] 74 | temp_graph = [[[0,0,0,0,0]for j in range(5)]for i in range(5)] 75 | cnt = 126 76 | 77 | Maaaaaaaaaze() 78 | if cnt == 126: 79 | print(-1) 80 | else: 81 | print(cnt) -------------------------------------------------------------------------------- /seoul_09_kyoohyunkim/BOJ/Silver II/Boj 21736/Baekjoon_21736.java: -------------------------------------------------------------------------------- 1 | package beak.Jul2023.p21736; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | import java.util.LinkedList; 7 | import java.util.Queue; 8 | import java.util.StringTokenizer; 9 | 10 | public class Baekjoon_21736 { 11 | 12 | static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 13 | static StringTokenizer st; 14 | static char[][] matrix; 15 | static int n,m; 16 | static int r,c; 17 | static int[][] deltas = { 18 | {1,0}, 19 | {-1,0}, 20 | {0,1}, 21 | {0,-1} 22 | }; 23 | 24 | static int count; 25 | static final char VISITED = '1'; 26 | static final char BLOCK = 'X'; 27 | static final char PEOPLE = 'P'; 28 | 29 | public static void main(String[] args) throws Exception { 30 | setVariables(); 31 | bfs(); 32 | System.out.println(count != 0 ? count : "TT"); 33 | 34 | } 35 | 36 | private static void setVariables() throws IOException { 37 | st = new StringTokenizer(br.readLine()); 38 | n = Integer.parseInt(st.nextToken()); 39 | m = Integer.parseInt(st.nextToken()); 40 | 41 | matrix = new char[n][m]; 42 | for (int i = 0; i < n; i++) { 43 | String line = br.readLine(); 44 | for(int j = 0; j q = new LinkedList<>(); 57 | q.add(new int[]{r,c}); 58 | matrix[r][c] = VISITED; 59 | 60 | while(!q.isEmpty()){ 61 | int[] poll = q.poll(); 62 | for(int[] del : deltas){ 63 | int nr = poll[0] + del[0]; 64 | int nc = poll[1] + del[1]; 65 | 66 | if(isIn(nr,nc) && matrix[nr][nc] != BLOCK&& matrix[nr][nc] != VISITED ){ 67 | if(matrix[nr][nc]==PEOPLE) 68 | count++; 69 | matrix[nr][nc] = VISITED; 70 | q.add(new int[]{nr,nc}); 71 | } 72 | } 73 | } 74 | } 75 | 76 | private static boolean isIn(int row, int col) { 77 | return row >= 0 && row < n && col >= 0 && col < m; 78 | } 79 | 80 | 81 | } -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Gold III/Boj 2206/Boj2206.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.Arrays; 5 | import java.util.LinkedList; 6 | import java.util.Queue; 7 | import java.util.StringTokenizer; 8 | 9 | public class Boj2206 { 10 | 11 | static int[][] map, visit; 12 | static int[] dx = {0,0,1,-1}; 13 | static int[] dy = {1,-1,0,0}; 14 | static int N, M; 15 | 16 | static int result = Integer.MAX_VALUE; 17 | 18 | static class Pos { 19 | int x; 20 | int y; 21 | int dis; 22 | int smash; 23 | 24 | Pos(int x, int y, int dis, int smash) { 25 | this.x = x; 26 | this.y = y; 27 | this.dis = dis; 28 | this.smash = smash; 29 | } 30 | } 31 | 32 | public static void main(String[] args) throws IOException { 33 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 34 | StringTokenizer st = new StringTokenizer(br.readLine()); 35 | 36 | int N = Integer.parseInt(st.nextToken()); 37 | int M = Integer.parseInt(st.nextToken()); 38 | 39 | map = new int[N + 1][M + 1]; 40 | visit = new int[N + 1][M + 1]; 41 | for(int i = 1; i <= N; i++) { 42 | String line = br.readLine(); 43 | 44 | for(int j = 1; j <= M; j++) { 45 | map[i][j] = Integer.parseInt(String.valueOf(line.charAt(j - 1))); 46 | } 47 | Arrays.fill(visit[i], Integer.MAX_VALUE); 48 | } 49 | 50 | Queue q = new LinkedList<>(); 51 | q.add(new Pos(1,1,1,0)); 52 | visit[1][1] = 0; 53 | 54 | while(!q.isEmpty()) { 55 | Pos now = q.poll(); 56 | 57 | if(now.x == M && now.y == N) { 58 | System.out.println(now.dis); 59 | return; 60 | } 61 | 62 | for(int i = 0; i < 4; i++) { 63 | int nextX = now.x + dx[i]; 64 | int nextY = now.y + dy[i]; 65 | 66 | if(nextX <= 0 || nextY <= 0 || nextX > M || nextY > N) 67 | continue; 68 | 69 | if(visit[nextY][nextX] > now.smash) { 70 | if(now.smash == 0 && map[nextY][nextX] == 1) { 71 | q.add(new Pos(nextX, nextY, now.dis + 1, 1)); 72 | visit[nextY][nextX] = now.smash + 1; 73 | } else if(map[nextY][nextX] == 0) { 74 | q.add(new Pos(nextX, nextY, now.dis + 1, now.smash)); 75 | visit[nextY][nextX] = now.smash; 76 | } 77 | } 78 | } 79 | } 80 | 81 | 82 | System.out.println(-1); 83 | } 84 | } -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Silver I/BoJ 1986/README.md: -------------------------------------------------------------------------------- 1 | # [백준 1986 체스](https://www.acmicpc.net/problem/1986) 2 | 3 | solved.ac Silver I 4 | 5 | ## 카테고리 6 | 7 | 구현 8 | 9 | ## 시간복잡도 10 | 11 | map의 가로세로 길이가 n,m으로 나뉘긴 하지만 최악의 경우 둘다 1000이므로 n이라고 간단하게 생각하겠다. 12 | Queen이 지나갈 수 있는 경로를 계산하는데 O(q X n) <- 여기서 q는 퀸의 개수이다(최대 100개). 13 | Knight 경로를 계산하는데 O(k) <- k는 마찬가지로 나이트의 개수이다(최대 100개). 14 | 15 | 구현 로직을 계산하는 부분보다 정답을 카운팅하는 부분이 시간복잡도가 더 크다. 16 | 모든 체스칸을 하나하나 방문하므로 O(n X m)이다. 17 | 18 | n,m의 최대 크기는 1000이므로 모든 과정이 충분히 2초 안에 들어오게 된다. 19 | 20 | ## 풀이 21 | 22 | 풀이는 핵심이 되는 세 부분만 짚고 넘어가겠다. 23 | 24 | 1. 폰은 움직이지 못하는 장애물이다. 아무런 코드도 적지 않고 그저 돌맹이로 보겠다. 다른 말이라고 다를 것 없다. 폰과 다르게 경로를 가질 뿐이지 움직이지 못하는 장애물인건 마찬가지다. 25 | 그래서 입력 받을 때 말의 위치를 map에 2로 저장했다. 26 | 27 | ```java 28 | //queen 입력 29 | st = new StringTokenizer(br.readLine()); 30 | int queenNum = Integer.parseInt(st.nextToken()); 31 | Pos[] queens = new Pos[queenNum]; 32 | for(int i = 0;i < queenNum;i++) { 33 | int y = Integer.parseInt(st.nextToken()); 34 | int x = Integer.parseInt(st.nextToken()); 35 | 36 | map[y][x] = 2; 37 | 38 | queens[i] = new Pos(x, y); 39 | } 40 | ``` 41 | 42 | 2. 다음은 퀸의 동작 과정이다. 퀸이 갈 수 있는 방향을 미리 배열로 만들어 두고 모든 방향으로 장애물을 마주치거나 벽을 마주칠 때까지 전진시킨다. 43 | 퀸의 경로에는 map에 1을 저장한다. 44 | ```java 45 | // 퀸 동작 46 | public static int[] queen_dx = {0,1,1,1,0,-1,-1,-1}; 47 | public static int[] queen_dy = {1,1,0,-1,-1,-1,0,1}; 48 | 49 | for(int i = 0; i < queenNum;i++) { 50 | int queenX = queens[i].x; 51 | int queenY = queens[i].y; 52 | 53 | for(int j = 0; j < 8; j++) { 54 | int nowX = queenX; 55 | int nowY = queenY; 56 | while(true) { 57 | int nextX = nowX + queen_dx[j]; 58 | int nextY = nowY + queen_dy[j]; 59 | 60 | if(nextX < 1 || nextX > m || nextY < 1 || nextY > n) 61 | break; 62 | if(map[nextY][nextX] == 2) 63 | break; 64 | 65 | map[nextY][nextX] = 1; 66 | nowX = nextX; 67 | nowY = nextY; 68 | } 69 | } 70 | } 71 | ``` 72 | 73 | 3. 나이트는 퀸처럼 앞으로 계속 나아가는 성질은 없기 때문에 갈 수 있는 경로만 미리 배열에 넣고 나이트 현재 위치에서 갈 수 있는 위치에 1만 저장해 주었다. 74 | 75 | ```java 76 | // 나이트 동작 77 | for(int i = 0; i < knightNum;i++) { 78 | int knightX = knights[i].x; 79 | int knightY = knights[i].y; 80 | 81 | for(int j = 0; j < 8; j++) { 82 | int nextX = knightX + knight_dx[j]; 83 | int nextY = knightY + knight_dy[j]; 84 | 85 | if(nextX < 1 || nextX > m || nextY < 1 || nextY > n) 86 | continue; 87 | if(map[nextY][nextX] == 2) 88 | continue; 89 | 90 | map[nextY][nextX] = 1; 91 | } 92 | } 93 | ``` 94 | 95 | 마지막엔 모든 체스판을 돌면서 0인 부분만 카운팅해주고 결과를 출력한다. 96 | 97 | ## 결과 98 | 99 | 결과 : [맞았습니다!!](https://www.acmicpc.net/source/63662079) 100 | -------------------------------------------------------------------------------- /seoul_09_kyoohyunkim/BOJ/Gold III/boj 10986/README.md: -------------------------------------------------------------------------------- 1 | # [BoJ 10986 나머지합](https://www.acmicpc.net/problem/10986) 2 | 3 | ## 카테고리 4 | 5 | 누적합, 수학 6 | 7 | ## 시간복잡도 8 | 9 | O(n) 10 | 11 | ## 해설 12 | 13 | ### 문제조건 14 | ![image](https://ssafy-enjoytrip-kkh.s3.ap-northeast-2.amazonaws.com/algo/%EB%82%98%EB%A8%B8%EC%A7%80%ED%95%A9_%EB%AC%B8%EC%A0%9C_%EC%A1%B0%EA%B1%B4.png) 15 | 16 | 17 | 문제 조건을 읽고 생각한 것은 다음과 같다. 18 | 19 | 1. '연속된 부분 구간의 합' -> 누적합과 관련된 문제구나. 20 | 2. '시간제한 1초' -> 좀 빡세게 구하는구나 21 | 3. '1<=N<=10^6' N이 높은 것을 보니 N log N에도 터질지도 모르겠구나. 22 | 4. '0 <= A <= 10^9' 누적합을 하다가 overflow가 날지도 모르겠다. 23 | 24 | 25 | 26 | ### 실패 풀이 27 | 28 | 첫번째로 풀이를 한 것은, 누적 합을 구하고, 그 안에서 r이 2인 중복 조합으로 풀어보았습니다. 29 | 제한 조건을 고려하지 않고 풀어서 당연하게도 시간초과가 발생했습니다. 30 | 10^6승에서 N^2을 하면 당연히 터진다는 생각을 하지 않고 접근을 했었습니다. 31 | 32 | 33 | 34 | ### 정답 풀이 35 | 36 | 누적 합을 구한 배열에서 서로 뺐을 때, M의 배수가 될 수 있는 규칙을 찾았습니다. 37 | 38 | 그 규칙은 누적합을 구한 구간들이 서로 M에 대한 나머지 연산의 결과가 같은 구간에서 뺀 경우에 M에 나누어 떨어지는 수가 나온다는 것 입니다. 39 | 40 | 아래 이미지를 보면 이해하기 쉽습니다. 41 | 42 | 43 | 44 | 처음에 주어진 입력값을 통해 누적합을 만들고, **M(3)에 대한 나머지 연산의 값이 같은 경우인 (1,7)과 (3,6,9)에 있는 누적합의 경우 서로 뺀다면, 45 | M의 배수의 형태가 나오는 것을 확인할 수 있습니다.** 46 | (누적합7은 1+2+3+1이기 때문에, 누적합 1을 뺄 경우 6이 된다.) 47 | 48 | ![image](https://ssafy-enjoytrip-kkh.s3.ap-northeast-2.amazonaws.com/algo/%EB%82%98%EB%A8%B8%EC%A7%80%ED%95%A9_%EC%9D%B4%EB%AF%B8%EC%A7%802.png) 49 | 50 | 51 | 위의 규칙을 활용하면, M으로 나누어 떨어지는 개수를 구하기 위해선, 각 나머지 연산의 결과에 대한 개수를 체크한다면 전부 끝났습니다. 52 | 53 | **사용 변수** 54 | ```java 55 | // 입출력을 위한 클래스 56 | BufferedReader br; 57 | StringTokenizer st; 58 | 59 | int n, int m; // 주어진 배열의 크기 n, 나누어 떨어져야 하는 수 m 60 | long[]arr; // 누적합을 기록할 배열 61 | int[]mods; // 나머지 연산 결과에 대한 카운팅 배열 62 | long result; // 결과계산 63 | ``` 64 | 65 | **누적합 배열 생성과 나머지 연산 결과 카운팅** 66 | 67 | 누적합 배열을 주어진 입력 크기인 n보다 1개 더 크게 만들고, 이전 인덱스(i-1)의 누적합과 새로 들어온 입력값을 더하는 것으로 계산했습니다. 68 | 그리고 그 누적값을 m과 나머지 연산하고 카운팅을 올려주었습니다. 69 | 70 | ```java 71 | for (int i = 1; i <= n; i++) { 72 | arr[i] = (arr[i - 1] %m + Long.parseLong(st.nextToken())% m)% m; 73 | int num = (int)(arr[i] % m); 74 | mods[num]++; 75 | } 76 | ``` 77 | 78 | **M으로 나누어 떨어지는 개수 세기** 79 | 80 | 앞선 설명으로 나머지 연산의 결과가 같은 애들끼리 뺀다면 M에 나누어 떨어진다는 것을 알 수 있었습니다. 빼기 위한 조합을 구하기 위해 nC2를 해서 그 값을 결과변수에 더해주었습니다. 81 | 그리고 이미 M으로 나누어 떨어지는 구간의 경우(mod == 0) 그 자체로 이미 답이 될 수 있기 때문에, 그 개수만큼 정답변수에 더해주었습니다. 82 | 83 | ```java 84 | long result = 0; 85 | for (int mod : mods) 86 | result += nCTwo(mod); 87 | result += mods[0]; 88 | System.out.println(result); 89 | 90 | private static long nCTwo(long n) { 91 | return (n * (n-1))/2; 92 | } 93 | ``` 94 | 95 | ### 결과 96 | 97 | 결과 : [맞았습니다!!](http://boj.kr/3860002f5b4e4cef87c6479a2f44296f)
98 | 메모리 : 167856 KB
99 | 시간 : 480 ms
100 | 언어 : JAVA
101 | 코드길이 : 1278 B -------------------------------------------------------------------------------- /seoul_21_minjaekim/MinCoding/Algorithm Tower/Implement Tower/5/README.md: -------------------------------------------------------------------------------- 1 | # [알고리즘 탑] 구현의 탑 5번 - 오목 2 | 3 | ## 카테고리 4 | 5 | 브루트포스 알고리즘, 구현 6 | 7 | ## 시간복잡도 8 | 9 | O(1) 10 | 11 | ## 해설 12 | 13 | DAT를 이용하기 위해 각 방향에서 바라본 연속된 돌의 개수를 저장할 배열을 선언한다. 14 | 15 | ```cpp 16 | int row_check[19] = { 0, }; 17 | int col_check[19] = { 0, }; 18 | int diag1_check[37] = { 0, }; 19 | int diag2_check[37] = { 0, }; 20 | ``` 21 | 22 | 오목판을 뒤에서부터 순회하며, 칸에 놓인 돌의 상태에 따라 DAT를 업데이트한다. 23 | 24 | ```cpp 25 | if (field[row][col] == 0) { 26 | row_check[row] = 0; 27 | col_check[col] = 0; 28 | diag1_check[row + col] = 0; 29 | diag2_check[row - col + 18] = 0; 30 | } 31 | else if (field[row][col] == 1) { 32 | row_check[row] = (row_check[row] > 0 ? row_check[row] + 1 : 1); 33 | col_check[col] = (col_check[col] > 0 ? col_check[col] + 1 : 1); 34 | diag1_check[row + col] = (diag1_check[row + col] > 0 ? diag1_check[row + col] + 1 : 1); 35 | diag2_check[row - col + 18] = (diag2_check[row - col + 18] > 0 ? diag2_check[row - col + 18] + 1 : 1); 36 | } 37 | else if (field[row][col] == 2) { 38 | row_check[row] = (row_check[row] < 0 ? row_check[row] - 1 : -1); 39 | col_check[col] = (col_check[col] < 0 ? col_check[col] - 1 : -1); 40 | diag1_check[row + col] = (diag1_check[row + col] < 0 ? diag1_check[row + col] - 1 : -1); 41 | diag2_check[row - col + 18] = (diag2_check[row - col + 18] < 0 ? diag2_check[row - col + 18] - 1 : -1); 42 | } 43 | ``` 44 | 45 | 연속된 5개의 돌이 있다면, 그 다음 칸에 놓인 돌의 상태에 따라 승리할 수 있는지 확인한다. 46 | 47 | ```cpp 48 | if (row_check[row] == 5 || col_check[col] == 5 || diag1_check[row + col] == 5 || diag2_check[row - col + 18] == 5) { 49 | if (row_check[row] == 5 && col > 0 && field[row][col - 1] == 1) 50 | continue; 51 | if (col_check[col] == 5 && row > 0 && field[row - 1][col] == 1) 52 | continue; 53 | if (diag1_check[row + col] == 5 && row > 0 && col < 18 && field[row - 1][col + 1] == 1) 54 | continue; 55 | if (diag2_check[row - col + 18] == 5 && row > 0 && col > 0 && field[row - 1][col - 1] == 1) 56 | continue; 57 | cout << 1 << '\n'; 58 | } 59 | else if (row_check[row] == -5 || col_check[col] == -5 || diag1_check[row + col] == -5 || diag2_check[row - col + 18] == -5) { 60 | if (row_check[row] == -5 && col > 0 && field[row][col - 1] == 2) 61 | continue; 62 | if (col_check[col] == -5 && row > 0 && field[row - 1][col] == 2) 63 | continue; 64 | if (diag1_check[row + col] == -5 && row > 0 && col < 18 && field[row - 1][col + 1] == 2) 65 | continue; 66 | if (diag2_check[row - col + 18] == -5 && row > 0 && col > 0 && field[row - 1][col - 1] == 2) 67 | continue; 68 | cout << 2 << '\n'; 69 | } 70 | else 71 | continue; 72 | ``` 73 | 74 | 가장 왼쪽, 위쪽에 놓인 돌을 출력한다. 75 | 76 | ```cpp 77 | if (diag1_check[row + col] == 5 || diag1_check[row + col] == -5) { 78 | row += 4; 79 | col -= 4; 80 | } 81 | cout << row + 1 << ' ' << col + 1 << '\n'; 82 | ``` 83 | 84 | ## 성능 요약 85 | 86 | 메모리: 2020 KB, 시간: 0 ms -------------------------------------------------------------------------------- /gumi_4_wonjulee/boj/boj2493/README.md: -------------------------------------------------------------------------------- 1 | # [Gold V] 탑 - 2493 2 | 3 | [문제 링크](https://www.acmicpc.net/problem/2493) 4 | 5 | ### 성능 요약 6 | 7 | 메모리: 126972 KB, 시간: 3452 ms 8 | 9 | ### 분류 10 | 11 | 자료 구조, 스택 12 | 13 | ### 문제 설명 14 | 15 |

KOI 통신연구소는 레이저를 이용한 새로운 비밀 통신 시스템 개발을 위한 실험을 하고 있다. 실험을 위하여 일직선 위에 N개의 높이가 서로 다른 탑을 수평 직선의 왼쪽부터 오른쪽 방향으로 차례로 세우고, 각 탑의 꼭대기에 레이저 송신기를 설치하였다. 모든 탑의 레이저 송신기는 레이저 신호를 지표면과 평행하게 수평 직선의 왼쪽 방향으로 발사하고, 탑의 기둥 모두에는 레이저 신호를 수신하는 장치가 설치되어 있다. 하나의 탑에서 발사된 레이저 신호는 가장 먼저 만나는 단 하나의 탑에서만 수신이 가능하다.

16 | 17 |

예를 들어 높이가 6, 9, 5, 7, 4인 다섯 개의 탑이 수평 직선에 일렬로 서 있고, 모든 탑에서는 주어진 탑 순서의 반대 방향(왼쪽 방향)으로 동시에 레이저 신호를 발사한다고 하자. 그러면, 높이가 4인 다섯 번째 탑에서 발사한 레이저 신호는 높이가 7인 네 번째 탑이 수신을 하고, 높이가 7인 네 번째 탑의 신호는 높이가 9인 두 번째 탑이, 높이가 5인 세 번째 탑의 신호도 높이가 9인 두 번째 탑이 수신을 한다. 높이가 9인 두 번째 탑과 높이가 6인 첫 번째 탑이 보낸 레이저 신호는 어떤 탑에서도 수신을 하지 못한다.

18 | 19 |

탑들의 개수 N과 탑들의 높이가 주어질 때, 각각의 탑에서 발사한 레이저 신호를 어느 탑에서 수신하는지를 알아내는 프로그램을 작성하라.

20 | 21 | ### 입력 22 | 23 |

첫째 줄에 탑의 수를 나타내는 정수 N이 주어진다. N은 1 이상 500,000 이하이다. 둘째 줄에는 N개의 탑들의 높이가 직선상에 놓인 순서대로 하나의 빈칸을 사이에 두고 주어진다. 탑들의 높이는 1 이상 100,000,000 이하의 정수이다.

24 | 25 | ### 출력 26 | 27 |

첫째 줄에 주어진 탑들의 순서대로 각각의 탑들에서 발사한 레이저 신호를 수신한 탑들의 번호를 하나의 빈칸을 사이에 두고 출력한다. 만약 레이저 신호를 수신하는 탑이 존재하지 않으면 0을 출력한다.

28 | 29 | 30 | --- 31 | 32 | ## 코드 33 | ```java 34 | 35 | public class Main { 36 | public static void main(String[] args) throws IOException { 37 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 38 | StringBuilder sb = new StringBuilder(); 39 | int N = Integer.parseInt(br.readLine()); 40 | Integer[] arr = new Integer[N]; 41 | Deque stack = new ArrayDeque<>(); 42 | List list = new LinkedList<>(); 43 | 44 | StringTokenizer st = new StringTokenizer(br.readLine()); 45 | 46 | // 1. 탑 입력받기 47 | for(int i=0; i=0; i--) { 53 | 54 | // 3. 스택이 비어있으면 push(addFirst) 55 | if(stack.isEmpty()) { 56 | stack.addFirst(arr[i]); 57 | } else { 58 | // 4. 현재 원소가 스택의 top보다 클 때: pop & list에 수신받은 탑 인덱스 add & 현재 원소 push 59 | if(stack.peek() < arr[i]) { 60 | while(!stack.isEmpty() && stack.peek() < arr[i]) { // 현재 원소보다 작은 값인 스택 요소를 전부 pop&list.add 61 | stack.poll(); 62 | list.add(i+1); 63 | } 64 | stack.addFirst(arr[i]); 65 | 66 | // 5. 현재 원소가 스택의 top보다 작을 때: 스택에 push 67 | } else if(stack.peek() >= arr[i]) { 68 | stack.addFirst(arr[i]); 69 | } 70 | } 71 | } 72 | 73 | // 배열을 한바퀴 다 돌고도 스택에 남아있는 탑들 (자기자신보다 높은 탑을 발견하지 못해 수신받지 못한 탑들) 74 | while(!stack.isEmpty()) { 75 | int idx = Arrays.asList(arr).indexOf(stack.pollLast()); 76 | list.add(arr.length-idx-1, 0); // 해당 원소 인덱스에 0 삽입 77 | } 78 | 79 | 80 | // 답 출력 81 | Collections.reverse(list); 82 | for(Integer i:list ) { 83 | sb.append(i).append(" "); 84 | } 85 | 86 | sb.deleteCharAt(sb.length() - 1); // 마지막 공백 제거 87 | System.out.println(sb); 88 | } 89 | } 90 | ``` -------------------------------------------------------------------------------- /seoul_x_hwijoonchoi/BOJ/boj16985/README.md: -------------------------------------------------------------------------------- 1 | # [BoJ 16985 bfs](https://www.acmicpc.net/problem/20529) 2 | 3 | solved.ac Gold 2 4 | 5 | ## 카테고리 6 | 7 | 완전탐색, bfs 8 | 9 | ## 시간복잡도 10 | 11 | O(N^5)? 12 | 13 | ## 풀이 14 | 15 | 1.입력받기 16 | 2. 층 별로 permuation(순열) 찾기 17 | 3. 회전 -> 90도씩 반복 18 | 4. 탐색 -> bfs 19 | 5. 최소 횟수 -> bfs돌린 결과 나올 때 마다 작은수 업데이트 20 | 21 | ```python 22 | from itertools import permutations 23 | from collections import deque 24 | from copy import deepcopy 25 | 26 | def Search(): 27 | global cnt 28 | for _ in range(4): 29 | for _ in range(4): 30 | for _ in range(4): 31 | for _ in range(4): 32 | for _ in range(4): 33 | Rotation(4) # 90도 회전 34 | cnt = min(cnt,Bfs(temp_graph)) # bfs로 현재 그래프에서의 최소 횟수 탐색 35 | if cnt == 12: 36 | return 37 | Rotation(3) 38 | Rotation(2) 39 | Rotation(1) 40 | Rotation(0) 41 | return 42 | 43 | def Maaaaaaaaaze(): 44 | for c in permutations(range(5)): 45 | for i in range(5): 46 | temp_graph[i] = graph[c[i]] # 경우의 수 47 | Search() # cnt return 48 | 49 | 50 | # 그래프 90도 회전 51 | def Rotation(n): 52 | temp = [[0 for j in range(5)] for i in range(5)] 53 | for i in range(5): 54 | for j in range(5): 55 | temp[i][j] = temp_graph[n][4-j][i] 56 | temp_graph[n] = temp 57 | return 58 | 59 | # bfs로 최소 횟수 탐색 60 | def Bfs(graph): 61 | if graph[0][0][0] == 0 or graph[4][4][4] == 0: # 시작이나 끝이 막혀있으면 탈출 불가 62 | return 126 63 | deq = deque() 64 | deq.append([0,0,0]) 65 | visit = [[[-1,-1,-1,-1,-1] for j in range(5)] for i in range(5)] 66 | 67 | visit[0][0][0] = 0 # 시작점 68 | dx = [0,0,1,-1,0,0] 69 | dy = [1,-1,0,0,0,0] 70 | dz = [0,0,0,0,1,-1] 71 | 72 | while deq: 73 | z,x,y = deq.popleft() 74 | if z == 4 and x == 4 and y == 4: #출구 도착 75 | return visit[z][x][y] 76 | 77 | if visit[z][x][y] > cnt: # 시간 단축(현재 탐색중인게 현재cnt값 보다 높아지면 중단) 78 | return visit[z][x][y] 79 | 80 | for i in range(6): 81 | nx = x + dx[i] 82 | ny = y + dy[i] 83 | nz = z + dz[i] 84 | 85 | if nx < 0 or nx > 4 or ny < 0 or ny > 4 or nz < 0 or nz > 4: 86 | continue 87 | if graph[nz][nx][ny] == 1 and visit[nz][nx][ny] == -1: 88 | visit[nz][nx][ny] = visit[z][x][y] + 1 89 | deq.append([nz,nx,ny]) 90 | # 출구 도달 못하면 91 | return 126 92 | 93 | # 1. 입력 받기 94 | graph = [[list(map(int,input().split())) for j in range(5)]for i in range(5)] 95 | temp_graph = [[[0,0,0,0,0]for j in range(5)]for i in range(5)] 96 | cnt = 126 97 | 98 | Maaaaaaaaaze() 99 | if cnt == 126: 100 | print(-1) 101 | else: 102 | print(cnt) 103 | ``` 104 | 105 | ## 결과 106 | 107 | 결과 : [맞았습니다!!] 108 | -------------------------------------------------------------------------------- /seoul_09_kyoohyunkim/BOJ/Silver II/Boj 21736/README.md: -------------------------------------------------------------------------------- 1 | # [BoJ 21736 헌내기는 친구가 필요해](https://www.acmicpc.net/problem/21736) 2 | 3 | ## 카테고리 4 | 5 | BFS 6 | 7 | ## 시간복잡도 8 | 9 | O(n^2) 10 | 11 | ## 해설 12 | 13 | ![image](https://github.com/SSAFY-10th/algorithm/assets/76154390/02285bff-a4d9-4100-bf69-34eec5eef796) 14 | 15 | 16 | 2차원 좌표평면에서 사방으로 이동하며, 목표(P)에 접근하게 될 경우 count를 +1 해주는 문제이다. 17 | 18 | 19 | 20 | **사용 변수** 21 | 22 | ```java 23 | static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 24 | static StringTokenizer st; 25 | static char[][] matrix; // 주어진 매트릭스 26 | static int n,m; // row와 column의 한계값 27 | static int r,c; // 시작 row, column 값 28 | static int[][] deltas = { // 사방 탐색용 2차원 배열 29 | {1,0}, 30 | {-1,0}, 31 | {0,1}, 32 | {0,-1} 33 | }; 34 | 35 | static int count; // 도연이가 만날 수 있는 사람 수 36 | static final char VISITED = '1'; // visited 배열 대체용 값 37 | static final char BLOCK = 'X'; // 도연이가 갈 수 없는 벽 38 | static final char PEOPLE = 'P'; // 도연이 친구^^ 39 | ``` 40 | 41 | 42 | 43 | 먼저 주어진 n과 m를 입력받고, matrix를 그려줍니다. 그리고 시작 지점의 좌표('I'인 부분)를 획득합니다. 44 | ```java 45 | private static void setVariables() throws IOException { 46 | st = new StringTokenizer(br.readLine()); 47 | n = Integer.parseInt(st.nextToken()); 48 | m = Integer.parseInt(st.nextToken()); 49 | 50 | matrix = new char[n][m]; 51 | for (int i = 0; i < n; i++) { 52 | String line = br.readLine(); 53 | for(int j = 0; j q = new LinkedList<>(); 71 | q.add(new int[]{r,c}); 72 | matrix[r][c] = VISITED; 73 | 74 | while(!q.isEmpty()){ 75 | int[] poll = q.poll(); 76 | for(int[] del : deltas){ 77 | int nr = poll[0] + del[0]; 78 | int nc = poll[1] + del[1]; 79 | 80 | if(isIn(nr,nc) && matrix[nr][nc] != BLOCK&& matrix[nr][nc] != VISITED ){ 81 | if(matrix[nr][nc]==PEOPLE) 82 | count++; 83 | matrix[nr][nc] = VISITED; 84 | q.add(new int[]{nr,nc}); 85 | } 86 | } 87 | } 88 | } 89 | 90 | private static boolean isIn(int row, int col) { 91 | return row >= 0 && row < n && col >= 0 && col < m; 92 | } 93 | ``` 94 | 95 | 96 | ## 성능 요약 97 | 98 | 메모리: 34820 KB, 시간: 328 ms 99 | 100 | 결과 : [맞았습니다!!](http://boj.kr/29639e6b3a0d425589d98cd8ab8e4da4) 101 | -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Silver II/BoJ 1138/README.md: -------------------------------------------------------------------------------- 1 | # [백준 1138 한 줄로 서기](https://www.acmicpc.net/problem/1138) 2 | 3 | solved.ac Silver II 4 | 5 | ## 카테고리 6 | 7 | 구현 8 | 9 | ## 시간복잡도 10 | 11 | 키가 1 ~ N인 모든 사람을 한번씩 모두 검사하므로 첫번째 for문에서 O(n), 12 | 안쪽에서 빈칸을 세며 적절한 위치를 찾는 두개의 while문에서 O(n)으로 13 | O(n ^ 2) 연산이다. 14 | 15 | ## 풀이 16 | **⏱️소요시간 40분**
17 | 이 문제는 본인보다 왼쪽에 키가 큰 사람의 수로 사람 순서를 구하는 문제로 풀이방법은 크게 아래와 같이 두가지로 나뉜다. 18 | 1. 키가 작은 사람부터 생각한다. 19 | 2. 키가 큰 사람부터 생각한다. 20 | 21 | 필자는 1번의 과정으로 문제를 풀었고 1번 과정을 상세히 설명한 후 2번 과정도 간략하게 알아볼 예정이다. 22 | 23 | 문제는 다음과 같은 법칙에 따라 접근했다. 24 | 1. 키가 가장 작은 사람은 왼쪽에 큰 사람 수만큼 빈칸을 두고 위치해야 한다. 25 | 2. 큰 사람 수만큼 빈칸을 두었지만 계산한 칸이 차있을 수 있다. 해당 칸에 있는 난쟁이같은 사람을 배려해줘야 하므로 빈칸이 나올 때 까지 오른쪽으로 이동하여 위치한다. 26 | 27 | 이해하기 쉽게 그림으로 이해를 돕겠다. 다음과 같은 입력을 받았다고 예를 들자. 28 | 29 | N = 7
30 | 6 1 1 1 2 0 0 31 | 32 | 키가 1인 사람은 본인보다 왼쪽 6칸에 큰 사람이 와야하므로 7번째 칸에 들어간다. 33 | |1|2|3|4|5|6|7| 34 | |--|--|--|--|--|--|--| 35 | |||||||1| 36 | 37 | 1이 이미 자리를 차지하고 있으므로 2는 그 다음 작은 사람이다. 2는 무조건 자기 왼쪽에 빈칸이 1개 있어야 한다. 38 | |1|2|3|4|5|6|7| 39 | |--|--|--|--|--|--|--| 40 | ||2|||||1| 41 | 42 | 1,2가 자리를 차지하고 있으므로 3은 그 다음 작은 사람이다. 3은 무조건 자기 왼쪽에 빈칸이 1개 있어야 한다. 43 | **하지만 해당 위치에는 이미 2가 있으므로 2번 원칙에 의해 오른쪽에서 가장 가까운 빈칸으로 찾아가야 한다.** 44 | |1|2|3|4|5|6|7| 45 | |--|--|--|--|--|--|--| 46 | ||2|3||||1| 47 | 48 | 그다음 작은 사람인 4도 왼쪽에 빈칸이 1개 있어야 한다. 하지만 2번, 3번 칸이 모두 차있으므로 4는 4번칸에 들어간다. 49 | |1|2|3|4|5|6|7| 50 | |--|--|--|--|--|--|--| 51 | ||2|3|4|||1| 52 | 53 | 이제 코드로 구현해보자. 결과를 저장할 자료구조는 1차원 배열로 선언하였다. 배열의 크기가 N + 1인 이유는... 없다. 컴파일 할 때 OutOfRangeException을 피하고 일단 로그를 찍어보기 위해서 넉넉하게 선언했다. 54 | ```java 55 | // 자료구조 선택 56 | int[] result = new int[N + 1]; 57 | ``` 58 | 59 | 1,2번 원칙은 아래와 같은 구현 코드로 변환된다. 60 | ```java 61 | // 구현 62 | for (int height = 1; height <= N; height++) { 63 | int left = arr[height]; // left는 키가 height인 사람 왼쪽에서 height 보다 큰 사람 수 64 | int idx = 0; // result 배열에 들어가야할 직접적인 인덱스 65 | int cnt = 0; // 현재까지 체크한 더 큰 사람 수 66 | while (cnt != left) { 67 | if(result[idx] == 0) cnt++; 68 | idx++; 69 | } 70 | while(result[idx] != 0) { 71 | idx++; 72 | } 73 | result[idx] = height; 74 | } 75 | ``` 76 | 77 | 간단한 로직으로 금방 구현이 가능하다. 78 | 79 | ## 결과 80 | 81 | 결과 : [맞았습니다!!](https://www.acmicpc.net/source/63759087) 82 | 83 | ## 추신 84 | 짧게 완전히 다른 접근 풀이도 보겠다. 아래는 위에서 언급한 키가 큰 사람부터 접근한 풀이법이다. 85 | ```java 86 | public static void main(String[] args) { 87 | Scanner scan = new Scanner(System.in); 88 | int n = scan.nextInt(); 89 | int [] tall = new int[n+1]; 90 | List ans = new ArrayList<>(); 91 | 92 | for(int i=1; i<=n; i++) { 93 | tall[i] = scan.nextInt(); 94 | } 95 | 96 | for(int i=n; i>=1; i--) { 97 | ans.add(tall[i], i); 98 | } 99 | 100 | for(int k : ans) { 101 | System.out.print(k+" "); 102 | } 103 | } 104 | ``` 105 | ~~Scanner부터 마음에 안든다.~~ 106 | ### 풀이 107 | 간단하다. 키가 큰 순으로 입력받은 키 대로 ArrayList 해당 위치에 삽입해주면 된다. 108 | 109 | 키가 4인 사람 -> 0 / 0번째에 삽입 -> [4] 110 | 111 | 키가 3인 사람 -> 1 / 1번째에 삽입 -> [4, 3] 112 | 113 | 키가 2인 사람 -> 1 / 1번째에 삽입 -> [4, 2, 3] 114 | 115 | 키가 1인 사람 -> 2 / 2번째에 삽입 -> [4, 2, 1, 3] 116 | 117 | ArrayList에서 주어진 인덱스에 원소를 추가하는 연산은 O(n)연산이다. 풀이를 써주신 분께서 왜 인덱스 추가 연산이 O(1)인 LinkedList를 사용하지 않았는가는 의문이 들지만 코드가 훨씬 직관적이고 간단해서 가져와봤다. -------------------------------------------------------------------------------- /seoul_15_suminkim/SWEA/Solution_d5_1248.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | import java.util.StringTokenizer; 7 | 8 | public class Solution_d5_1248 { 9 | 10 | static int v; 11 | static List[] adj; 12 | static int[][] sTable; 13 | static int[] depth; 14 | static int[] subTree; 15 | static int k; 16 | 17 | public static void main(String[] args) throws IOException { 18 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 19 | int tc = Integer.parseInt(br.readLine()); 20 | StringBuilder sb = new StringBuilder(); 21 | for (int t = 1; t <= tc; t++) { 22 | StringTokenizer st = new StringTokenizer(br.readLine()); 23 | v = Integer.parseInt(st.nextToken()); 24 | k = 32 - Integer.numberOfLeadingZeros(v); 25 | int e = Integer.parseInt(st.nextToken()); 26 | int v1 = Integer.parseInt(st.nextToken()); 27 | int v2 = Integer.parseInt(st.nextToken()); 28 | setGraph(br.readLine(), e); 29 | setParent(); 30 | setSTable(); 31 | setSubTree(); 32 | int lca = lca(v1, v2); 33 | sb.append("#" + t + " " + lca + " " + subTree[lca] + "\n"); 34 | } 35 | System.out.println(sb); 36 | } 37 | 38 | private static void setGraph(String readLine, int e) { 39 | StringTokenizer st = new StringTokenizer(readLine); 40 | adj = new List[v + 1]; 41 | for (int i = 1; i <= v; i++) { 42 | adj[i] = new LinkedList<>(); 43 | } 44 | for (int i = 0; i < e; i++) { 45 | int v1 = Integer.parseInt(st.nextToken()); 46 | int v2 = Integer.parseInt(st.nextToken()); 47 | adj[v1].add(v2); 48 | adj[v2].add(v1); 49 | } 50 | } 51 | 52 | private static void setParent() { 53 | sTable = new int[v + 1][k]; 54 | depth = new int[v + 1]; 55 | sTable[1][0] = 1; 56 | setParent(1); 57 | } 58 | 59 | private static void setParent(int root) { 60 | for (int child : adj[root]) { 61 | if (sTable[child][0] > 0) continue; 62 | sTable[child][0] = root; 63 | depth[child] = depth[root] + 1; 64 | setParent(child); 65 | } 66 | } 67 | 68 | private static void setSTable() { 69 | for (int d = 1; d < k; d++) { 70 | for (int i = 1; i <= v; i++) { 71 | sTable[i][d] = sTable[sTable[i][d - 1]][d - 1]; 72 | } 73 | } 74 | } 75 | 76 | private static void setSubTree() { 77 | subTree = new int[v + 1]; 78 | setSubTree(1); 79 | } 80 | 81 | private static int setSubTree(int root) { 82 | if (subTree[root] != 0) return subTree[root]; 83 | subTree[root] = 1; 84 | for (int child : adj[root]) { 85 | if (sTable[child][0] != root) continue; 86 | subTree[root] += setSubTree(child); 87 | } 88 | return subTree[root]; 89 | } 90 | 91 | private static int lca(int v1, int v2) { 92 | // v1이 더 깊은쪽이 되도록 변환 93 | if (depth[v1] < depth[v2]) { 94 | int temp = v1; 95 | v1 = v2; 96 | v2 = temp; 97 | } 98 | // v1, v2 depth 맞추기 99 | for (int i = k - 1; i >= 0; i--) { 100 | if (depth[v1] - depth[v2] >= (1 << i)) { 101 | v1 = sTable[v1][i]; 102 | } 103 | } 104 | // 같아지면 같아진값 반환 105 | if (v1 == v2) return v1; 106 | // 공통 조상 찾기 : 가장 위쪽의 서로 다른 조상 107 | for (int i = k - 1; i >= 0; i--) { 108 | if (sTable[v1][i] != sTable[v2][i]) { 109 | v1 = sTable[v1][i]; 110 | v2 = sTable[v2][i]; 111 | } 112 | } 113 | return sTable[v1][0]; 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /seoul_21_minjaekim/MinCoding/Algorithm Tower/Implement Tower/5/min_implement_tower_5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ios_base::sync_with_stdio(false); 7 | cin.tie(nullptr); 8 | cout.tie(nullptr); 9 | 10 | int field[19][19]; 11 | for (auto& row : field) 12 | for (int& element : row) 13 | cin >> element; 14 | 15 | int row_check[19] = { 0, }; 16 | int col_check[19] = { 0, }; 17 | int diag1_check[37] = { 0, }; 18 | int diag2_check[37] = { 0, }; 19 | 20 | for (int row = 18; row >= 0; --row) { 21 | for (int col = 18; col >= 0; --col) { 22 | if (field[row][col] == 0) { 23 | row_check[row] = 0; 24 | col_check[col] = 0; 25 | diag1_check[row + col] = 0; 26 | diag2_check[row - col + 18] = 0; 27 | } 28 | else if (field[row][col] == 1) { 29 | row_check[row] = (row_check[row] > 0 ? row_check[row] + 1 : 1); 30 | col_check[col] = (col_check[col] > 0 ? col_check[col] + 1 : 1); 31 | diag1_check[row + col] = (diag1_check[row + col] > 0 ? diag1_check[row + col] + 1 : 1); 32 | diag2_check[row - col + 18] = (diag2_check[row - col + 18] > 0 ? diag2_check[row - col + 18] + 1 : 1); 33 | } 34 | else if (field[row][col] == 2) { 35 | row_check[row] = (row_check[row] < 0 ? row_check[row] - 1 : -1); 36 | col_check[col] = (col_check[col] < 0 ? col_check[col] - 1 : -1); 37 | diag1_check[row + col] = (diag1_check[row + col] < 0 ? diag1_check[row + col] - 1 : -1); 38 | diag2_check[row - col + 18] = (diag2_check[row - col + 18] < 0 ? diag2_check[row - col + 18] - 1 : -1); 39 | } 40 | if (row_check[row] == 5 || col_check[col] == 5 || diag1_check[row + col] == 5 || diag2_check[row - col + 18] == 5) { 41 | if (row_check[row] == 5 && col > 0 && field[row][col - 1] == 1) 42 | continue; 43 | if (col_check[col] == 5 && row > 0 && field[row - 1][col] == 1) 44 | continue; 45 | if (diag1_check[row + col] == 5 && row > 0 && col < 18 && field[row - 1][col + 1] == 1) 46 | continue; 47 | if (diag2_check[row - col + 18] == 5 && row > 0 && col > 0 && field[row - 1][col - 1] == 1) 48 | continue; 49 | cout << 1 << '\n'; 50 | } 51 | else if (row_check[row] == -5 || col_check[col] == -5 || diag1_check[row + col] == -5 || diag2_check[row - col + 18] == -5) { 52 | if (row_check[row] == -5 && col > 0 && field[row][col - 1] == 2) 53 | continue; 54 | if (col_check[col] == -5 && row > 0 && field[row - 1][col] == 2) 55 | continue; 56 | if (diag1_check[row + col] == -5 && row > 0 && col < 18 && field[row - 1][col + 1] == 2) 57 | continue; 58 | if (diag2_check[row - col + 18] == -5 && row > 0 && col > 0 && field[row - 1][col - 1] == 2) 59 | continue; 60 | cout << 2 << '\n'; 61 | } 62 | else 63 | continue; 64 | if (diag1_check[row + col] == 5 || diag1_check[row + col] == -5) { 65 | row += 4; 66 | col -= 4; 67 | } 68 | cout << row + 1 << ' ' << col + 1 << '\n'; 69 | return 0; 70 | } 71 | } 72 | cout << 0 << '\n'; 73 | 74 | return 0; 75 | } -------------------------------------------------------------------------------- /seoul_21_minjaekim/Softeer/HSAT_7th/2/README.md: -------------------------------------------------------------------------------- 1 | # [7차 Softeer 정기 역량 진단] 2번 - 순서대로 방문하기 2 | 3 | ## 카테고리 4 | 5 | DFS, 백트래킹 6 | 7 | ## 시간복잡도 8 | 9 | `O(4 ^ (N ^ 2))` 10 | 11 | ## 문제 12 | 13 | 주어진 지도에서 입력 받은 방문해야 하는 지점을 순서대로 방문할 수 있는 서로 다른 방법의 수를 구하는 프로그램을 작성하시오. 14 | 15 | 입력 받은 방문해야 하는 지점의 첫 번째 지점이 출발지이다. 16 | 17 | 입력 받은 방문해야 하는 지점의 마지막 지점이 도착지이다. 18 | 19 | 한 번 지났던 지점은 다시 지날 수 없다. 20 | 21 | ## 제약 조건 22 | 23 | - 2 ≤ n ≤ 4 24 | - 2 ≤ m ≤ n^2 25 | 26 | ## 시간 제약 27 | 28 | - Java : 1초 29 | - C++ : 1초 30 | - Python : 1초 31 | 32 | ## 입력 형식 33 | 34 | - 첫 번째 줄에 격자의 크기 `n`, 순서대로 방문해야 하는 칸의 수 `m`이 주어진다. 35 | - 두 번째 줄부터 `n`개의 줄에 걸쳐 각 행에 해당하는 `n`개의 수가 `0` 혹은 `1`로 주어진다. `0`은 빈 칸, `1`은 벽을 의미한다. 36 | - `n + 2` 번째 줄부터 `m`개의 줄에 걸쳐 방문해야 하는 `m`개의 칸의 위치가 `row`, `col` 쌍으로 주어진다. 주어지는 칸에는 벽이 없고, 동일한 칸이 여러 번 주어지는 경우는 없다. 37 | 38 | ## 출력 형식 39 | 40 | 차량이 `m`개의 지점을 순서대로 방문할 수 있는 서로 다른 방법의 수를 출력한다. 41 | 만약 가능한 방법이 없다면 `0`을 출력한다. 42 | 43 | ## 해설 44 | 45 | 각 지점의 행, 열 정보를 저장하는 구조체 `Pos`와 각 방향의 행, 열 정보를 저장하는 구조체 `Directions`를 정의한다. 46 | 47 | `direc` 배열에는 각 방향으로의 행, 열 정보를 저장한다. 48 | 49 | ```cpp 50 | struct Pos { 51 | int row, col; 52 | }; 53 | 54 | struct Directions { 55 | int drow, dcol; 56 | }; 57 | 58 | Directions direc[4] = { 59 | {-1, 0}, 60 | {0, -1}, 61 | {1, 0}, 62 | {0, 1} 63 | }; 64 | ``` 65 | 66 | 방문 순서를 저장하는 `pos_map` 배열과 방문 여부를 저장하는 `visited` 배열을 정의한다. 67 | 68 | ```cpp 69 | bool visited[4][4]; 70 | int pos_map[4][4]; 71 | ``` 72 | 73 | 벽의 위치를 `visited`에 방문함으로 표시한다. 74 | 75 | ```cpp 76 | int n, m; 77 | cin >> n >> m; 78 | 79 | for (int i = 0; i < n; ++i) 80 | for (int j = 0; j < n; ++j) 81 | cin >> visited[i][j]; 82 | ``` 83 | 84 | 첫 번째 지점의 정보를 입력받고, `visited`에 방문함으로 표시한다. 85 | 86 | ```cpp 87 | int row, col; 88 | Pos start_pos; 89 | cin >> row >> col; 90 | visited[row - 1][col - 1] = true; 91 | start_pos.row = row - 1; 92 | start_pos.col = col - 1; 93 | ``` 94 | 95 | 두 번째 지점부터 `m`개의 지점의 정보를 입력받고, `pos_map`에 지점의 순서를 저장한다. 96 | 97 | ```cpp 98 | for (int i = 2; i <= m; ++i) { 99 | Pos pos; 100 | cin >> row >> col; 101 | pos_map[row - 1][col - 1] = i; 102 | pos.row = row - 1; 103 | pos.col = col - 1; 104 | } 105 | ``` 106 | 107 | `dfs` 함수를 통해 경로의 수를 구한다. 108 | 109 | ```cpp 110 | cout << dfs(n, m, start_pos) << '\n'; 111 | ``` 112 | 113 | 현재 지점의 정보를 확인해 백트래킹을 수행한다. 114 | 115 | 현재 지점이 도착지라면 `1`을 반환한다. 116 | 117 | 현재 지점이 도착지가 아니고, 현재 지점이 이번에 방문할 순서의 지점이라면 `pos_idx`를 증가시킨다. 118 | 119 | 현재 지점이 이번에 방문할 순서의 지점이 아니라면 `0`을 반환한다. 120 | 121 | ```cpp 122 | int cur_idx = pos_map[cur_pos.row][cur_pos.col]; 123 | if (cur_idx == end_idx && cur_idx == pos_idx) 124 | return 1; 125 | else if (cur_idx == pos_idx) 126 | ++pos_idx; 127 | else if (cur_idx) 128 | return 0; 129 | ``` 130 | 131 | `dfs` 알고리즘을 이용해 다음 지점이 이미 방문한 지점이 아니라면, 다음 지점으로 재귀적으로 이동해 경로의 수를 구한다. 132 | 133 | 리턴을 이용해 목적지까지 도착 가능한 경로의 수를 누적시킨다. 134 | 135 | ```cpp 136 | int count = 0; 137 | for (auto d : direc) { 138 | Pos next_pos; 139 | next_pos.row = cur_pos.row + d.drow; 140 | next_pos.col = cur_pos.col + d.dcol; 141 | 142 | if (next_pos.row < 0 || next_pos.row >= n || next_pos.col < 0 || next_pos.col >= n || visited[next_pos.row][next_pos.col]) 143 | continue; 144 | 145 | visited[next_pos.row][next_pos.col] = true; 146 | count += dfs(n, end_idx, next_pos, pos_idx); 147 | visited[next_pos.row][next_pos.col] = false; 148 | } 149 | return count; 150 | ``` 151 | 152 | ## 문제 분석 153 | 154 | `dfs` 문제에 특정 지점들을 순서대로 방문하는 조건이 추가된 문제이다. 155 | 156 | 해당 지점들을 알맞는 순서에 방문하지 않으면 `백트래킹`을 통해 시간을 단축시킬 수 있다. 157 | -------------------------------------------------------------------------------- /seoul_10_parkhoje/boj15683/boj15683.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | import java.util.ArrayList; 3 | import java.util.StringTokenizer; 4 | 5 | public class Main { 6 | 7 | static int N, M; 8 | static int[] dx = {0, 0, 1, -1}; 9 | static int[] dy = {1, -1, 0, 0}; 10 | static ArrayList cctvInfo; 11 | static int[][] office; 12 | static int answer; 13 | static final int[][][] cctvDirection = { 14 | {}, 15 | {{0}, {1}, {2}, {3}}, 16 | {{0, 1}, {2, 3}}, 17 | {{0, 3}, {0, 2}, {1, 2}, {1, 3}}, 18 | {{0, 1, 3}, {0, 2, 3}, {0, 1, 2}, {1, 2, 3}}, 19 | {{0, 1, 2, 3}} 20 | }; 21 | 22 | public static void main(String[] args) throws IOException { 23 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 24 | BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); 25 | 26 | StringTokenizer tokenizer = new StringTokenizer(br.readLine()); 27 | N = Integer.parseInt(tokenizer.nextToken()); 28 | M = Integer.parseInt(tokenizer.nextToken()); 29 | 30 | office = new int[N][M]; 31 | cctvInfo = new ArrayList<>(); 32 | for (int i = 0; i < N; i++) { 33 | tokenizer = new StringTokenizer(br.readLine()); 34 | for (int j = 0; j < M; j++) { 35 | office[i][j] = Integer.parseInt(tokenizer.nextToken()); 36 | if (office[i][j] >= 1 && office[i][j] <= 5) { 37 | cctvInfo.add(new Cctv(i, j, office[i][j], 0)); 38 | } 39 | } 40 | } 41 | 42 | answer = Integer.MAX_VALUE; 43 | findDirCase(0, cctvInfo.size()); 44 | 45 | bw.write(String.valueOf(answer)); 46 | bw.flush(); 47 | bw.close(); 48 | br.close(); 49 | } 50 | 51 | private static void findDirCase(int index, int size) { 52 | if (index == size) { 53 | answer = Math.min(getBlindSpot(), answer); 54 | return; 55 | } 56 | 57 | Cctv cctv = cctvInfo.get(index); 58 | for (int i = 0; i < cctvDirection[cctv.number].length; i++) { 59 | cctv.dir = i; 60 | findDirCase(index + 1, size); 61 | } 62 | } 63 | 64 | private static int getBlindSpot() { 65 | boolean[][] visited = new boolean[N][M]; 66 | for (Cctv cctv : cctvInfo) { 67 | for (int dir : cctvDirection[cctv.number][cctv.dir]) { 68 | visited[cctv.x][cctv.y] = true; 69 | int nx = cctv.x + dx[dir]; 70 | int ny = cctv.y + dy[dir]; 71 | while (isInRange(nx, ny) && office[nx][ny] != 6) { 72 | visited[nx][ny] = true; 73 | nx += dx[dir]; 74 | ny += dy[dir]; 75 | } 76 | } 77 | } 78 | 79 | int size = 0; 80 | for (int x = 0; x < N; x++) { 81 | for (int y = 0; y < M; y++) { 82 | if (visited[x][y] || office[x][y] == 6) { 83 | size++; 84 | } 85 | } 86 | } 87 | 88 | return N * M - size; 89 | } 90 | 91 | private static boolean isInRange(int x, int y) { 92 | return x >= 0 && y >= 0 && x < N && y < M; 93 | } 94 | 95 | static class Cctv { 96 | int x, y, number, dir; 97 | 98 | public Cctv(int x, int y, int number, int dir) { 99 | this.x = x; 100 | this.y = y; 101 | this.number = number; 102 | this.dir = dir; 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Team 2 | 3 | 4 | | [![Minjae Kim](https://avatars.githubusercontent.com/u/33440010)](https://github.com/minjae9610) | ![Choi Jun Ho](https://avatars.githubusercontent.com/u/39554558) | ![gabalja](https://avatars.githubusercontent.com/u/80046476) | ![Ho Je](https://avatars.githubusercontent.com/u/83208807) | ![WhalesBob](https://avatars.githubusercontent.com/u/96509257) | 5 | |:------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------------------------------:| :----------------------------------------------------------------------------------------: | :----------------------------------------------------------: | :------------------------------------------------------------: | 6 | | [Minjae Kim](https://github.com/minjae9610) | [Choi Jun Ho](https://github.com/junhochoi-dev) | [gabalja](https://github.com/gabalja) | [Ho Je](https://github.com/zini9188) | [WhalesBob](https://github.com/WhalesBob) | 7 | | [![Cha Cha](https://avatars.githubusercontent.com/u/90785316)](https://github.com/ChaCha3088) | [![3o14](https://avatars.githubusercontent.com/u/101818687)](https://github.com/3o14) | [![Yg-Hong](https://avatars.githubusercontent.com/u/89956603)](https://github.com/Yg-Hong) | ![KIM SEI](https://avatars.githubusercontent.com/u/74192619) | [![Sumin Kim](https://avatars.githubusercontent.com/u/87856793)](https://github.com/Sumin-Kim-dev) | 8 | | [Cha Cha](https://github.com/ChaCha3088) | [3o14](https://github.com/3o14) | [Yg-Hong](https://github.com/Yg-Hong) | [KIM SEI](https://github.com/KIMSEI1124) | [Sumin Kim](https://github.com/Sumin-Kim-dev) | 9 | | [![BELLDAY](https://avatars.githubusercontent.com/u/92672351)](https://github.com/bellday) | [![kgh2120](https://avatars.githubusercontent.com/u/76154390)](https://github.com/kgh2120) | [![kimjunha1575](https://avatars.githubusercontent.com/u/121413081)](https://github.com/kimjunha1575) | 10 | | [BELLDAY](https://github.com/bellday) | [kgh2120](https://github.com/kgh2120) | [kimjunha1575](https://github.com/kimjunha1575) | 11 | 12 | 13 | ## Git Commit Message 14 | 15 | | _Type_ | _Subject_ | 16 | | :-------------- | :--------------------------- | 17 | | **[lang name]** | 문제 해결 | 18 | | **[fix]** | 수정 | 19 | | **[docs]** | 문서 (문서 추가, 수정, 삭제) | 20 | | **[chore]** | 빌드, 설정 파일 | 21 | 22 | ex) [Type] #이슈번호 커밋메세지 `git commit -m '[python] #12 백준 1237'` 23 | 24 | ## Git Branch 25 | 26 | | 브랜치명 | 작업 내용 | 27 | | :------------------------------------------- | :--------------- | 28 | | **main** | 공용 | 29 | | **algo/본인아이디/작업구분(ex.날짜,작업명)** | 문제 해결 브랜치 | 30 | 31 | ## File Tree 32 | 33 | / **캠퍼스_반_이름(영어로)** / **Problem ID** / **solve file, problem info file** 34 | 35 | ## Branching model 36 | 37 | ![Branching model](https://github.com/SSAFY-10th/algorithm/assets/33440010/3d370256-db41-43c5-8043-cc50d0b4a880) 38 | -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Gold V/Boj 15591/README.md: -------------------------------------------------------------------------------- 1 | # [백준 15591 MooTube(Silver)](https://www.acmicpc.net/problem/15591) 2 | 3 | solved.ac Gold V 4 | 5 | ## 카테고리 6 | 7 | 그래프 이론, 그래프 탐색, 너비 우선 탐색(bfs) 8 | 9 | ## 전체 코드 10 | 11 | ```java 12 | import java.io.BufferedReader; 13 | import java.io.IOException; 14 | import java.io.InputStreamReader; 15 | import java.util.ArrayList; 16 | import java.util.LinkedList; 17 | import java.util.Queue; 18 | import java.util.StringTokenizer; 19 | 20 | public class Main { 21 | 22 | public static void main(String[] args) throws IOException { 23 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 24 | StringTokenizer st = new StringTokenizer(br.readLine()); 25 | 26 | int N = Integer.parseInt(st.nextToken()); 27 | int Q = Integer.parseInt(st.nextToken()); 28 | ArrayList> graph = new ArrayList<>(); 29 | for(int i = 0; i <= N; i++) { 30 | graph.add(new ArrayList<>()); 31 | } 32 | 33 | int a, b, weight; 34 | for(int i = 0 ; i < N - 1;i++) { 35 | st = new StringTokenizer(br.readLine()); 36 | a = Integer.parseInt(st.nextToken()); 37 | b = Integer.parseInt(st.nextToken()); 38 | weight = Integer.parseInt(st.nextToken()); 39 | 40 | graph.get(a).add(new int[] {b, weight}); 41 | graph.get(b).add(new int[] {a, weight}); 42 | } 43 | 44 | StringBuilder sb = new StringBuilder(); 45 | boolean[] visit; 46 | int k, v, result; 47 | 48 | while(Q-- > 0) { 49 | st = new StringTokenizer(br.readLine()); 50 | k = Integer.parseInt(st.nextToken()); 51 | v = Integer.parseInt(st.nextToken()); 52 | 53 | // 다음 영상과의 유사도(USADO)가 K보다 작은 경우 다음 영상은 추천되지 않는다고 생각 54 | result = 0; 55 | visit = new boolean[N + 1]; 56 | 57 | Queue q = new LinkedList<>(); 58 | q.add(v); 59 | visit[v] = true; 60 | while(!q.isEmpty()) { 61 | int now = q.poll(); 62 | 63 | for(int[] edge : graph.get(now)) { 64 | if(!visit[edge[0]] && edge[1] >= k) { 65 | q.add(edge[0]); 66 | visit[edge[0]] = true; 67 | result++; 68 | } 69 | } 70 | } 71 | 72 | sb.append(result).append("\n"); 73 | } 74 | 75 | System.out.println(sb); 76 | } 77 | } 78 | ``` 79 | 80 | ## 시간복잡도 81 | 82 | 농부는 Q번 질문하고 한번의 질문에서 BFS를 수행한다. BFS의 시간복잡도는 익히 알려진 대로 O(N + E)이다. 따라서 위 코드의 시간복잡도는 O(Q X N)이다. 83 | 84 | ## 풀이 85 | 86 | **⏱️소요시간 60분**
87 | 88 | 그래프 문제를 너무 오랜만에 풀어서 그런가 정답과 방향이 먼 곳으로 밖에 생각이 안갔다. 답은 생각보다 간단한 곳에 있었다. 처음에는 `임의의 두 쌍 사이의 동영상의 USADO를 그 경로의 모든 연결들의 USADO 중 최솟값으로 하기로 했다.`라는 문장 때문에 동영상들의 유사도를 모두 그래프 탐색하여 map에 저장하는 방법을 고민했지만 그럴 필요 없었다. 89 | 90 | Queue로 넣는 탐색 조건에 유사도가 K보다 크거나 같은 노드들만 넣는다면 USADO에 대해서 특별하게 계산하지 않아도 된다. USADO가 K보다 작은 노드들은 더이상 탐색을 해봐야 USADO가 K보다 작아진다. 따라서 문제는 그냥 BFS 문제이다. 91 | 92 | ```java 93 | while(Q-- > 0) { 94 | st = new StringTokenizer(br.readLine()); 95 | k = Integer.parseInt(st.nextToken()); 96 | v = Integer.parseInt(st.nextToken()); 97 | 98 | // 다음 영상과의 유사도(USADO)가 K보다 작은 경우 다음 영상은 추천되지 않는다고 생각 99 | result = 0; 100 | visit = new boolean[N + 1]; 101 | 102 | Queue q = new LinkedList<>(); 103 | q.add(v); 104 | visit[v] = true; 105 | while(!q.isEmpty()) { 106 | int now = q.poll(); 107 | 108 | for(int[] edge : graph.get(now)) { 109 | if(!visit[edge[0]] && edge[1] >= k) { 110 | q.add(edge[0]); 111 | visit[edge[0]] = true; 112 | result++; 113 | } 114 | } 115 | } 116 | 117 | sb.append(result).append("\n"); 118 | } 119 | ``` 120 | 121 | 출력이 최대 5000번 일어난다. 이런 경우 꼭 StringBuilder를 사용해주자. 122 | 123 | ## 결과 124 | 125 | 결과 : [맞았습니다!!](https://www.acmicpc.net/source/64448510)
126 | 메모리 : 311668 KB
127 | 시간 : 1844 ms
128 | 언어 : JAVA
129 | 코드길이 : 1746 B
130 | -------------------------------------------------------------------------------- /gumi_4_wonjulee/boj/boj1244/README.md: -------------------------------------------------------------------------------- 1 | # [[Silver IV] 스위치 켜고 끄기 - 1244](https://www.acmicpc.net/problem/1244) 2 | 3 | ### 성능 요약 4 | 메모리: 14492 KB, 시간: 144 ms 5 | 6 | ### 분류 7 | 구현, 시뮬레이션 8 | 9 | ### 문제 설명 10 | 1부터 연속적으로 번호가 붙어있는 스위치들이 있다. 스위치는 켜져 있거나 꺼져있는 상태이다. <그림 1>에 스위치 8개의 상태가 표시되어 있다. ‘1’은 스위치가 켜져 있음을, ‘0’은 꺼져 있음을 나타낸다. 그리고 학생 몇 명을 뽑아서, 학생들에게 1 이상이고 스위치 개수 이하인 자연수를 하나씩 나누어주었다. 학생들은 자신의 성별과 받은 수에 따라 아래와 같은 방식으로 스위치를 조작하게 된다. 11 | 12 | 남학생은 스위치 번호가 자기가 받은 수의 배수이면, 그 스위치의 상태를 바꾼다. 즉, 스위치가 켜져 있으면 끄고, 꺼져 있으면 켠다. <그림 1>과 같은 상태에서 남학생이 3을 받았다면, 이 학생은 <그림 2>와 같이 3번, 6번 스위치의 상태를 바꾼다. 13 | 14 | 여학생은 자기가 받은 수와 같은 번호가 붙은 스위치를 중심으로 좌우가 대칭이면서 가장 많은 스위치를 포함하는 구간을 찾아서, 그 구간에 속한 스위치의 상태를 모두 바꾼다. 이때 구간에 속한 스위치 개수는 항상 홀수가 된다. 15 | 16 | 스위치 번호 ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ 17 | 스위치 상태 0 1 0 1 0 0 0 1 18 | <그림 1> 19 | 20 | 예를 들어 <그림 2>에서 여학생이 3을 받았다면, 3번 스위치를 중심으로 2번, 4번 스위치의 상태가 같고 1번, 5번 스위치의 상태가 같으므로, <그림 3>과 같이 1번부터 5번까지 스위치의 상태를 모두 바꾼다. 만약 <그림 2>에서 여학생이 4를 받았다면, 3번, 5번 스위치의 상태가 서로 다르므로 4번 스위치의 상태만 바꾼다. 21 | 22 | 스위치 번호 ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ 23 | 스위치 상태 0 1 1 1 0 1 0 1 24 | <그림 2> 25 | 26 | 스위치 번호 ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ 27 | 스위치 상태 1 0 0 0 1 1 0 1 28 | <그림 3> 29 | 30 | 입력으로 스위치들의 처음 상태가 주어지고, 각 학생의 성별과 받은 수가 주어진다. 학생들은 입력되는 순서대로 자기의 성별과 받은 수에 따라 스위치의 상태를 바꾸었을 때, 스위치들의 마지막 상태를 출력하는 프로그램을 작성하시오. 31 | 32 | ### 입력 33 | 첫째 줄에는 스위치 개수가 주어진다. 스위치 개수는 100 이하인 양의 정수이다. 둘째 줄에는 각 스위치의 상태가 주어진다. 켜져 있으면 1, 꺼져있으면 0이라고 표시하고 사이에 빈칸이 하나씩 있다. 셋째 줄에는 학생수가 주어진다. 학생수는 100 이하인 양의 정수이다. 넷째 줄부터 마지막 줄까지 한 줄에 한 학생의 성별, 학생이 받은 수가 주어진다. 남학생은 1로, 여학생은 2로 표시하고, 학생이 받은 수는 스위치 개수 이하인 양의 정수이다. 학생의 성별과 받은 수 사이에 빈칸이 하나씩 있다. 34 | 35 | ### 출력 36 | 스위치의 상태를 1번 스위치에서 시작하여 마지막 스위치까지 한 줄에 20개씩 출력한다. 예를 들어 21번 스위치가 있다면 이 스위치의 상태는 둘째 줄 맨 앞에 출력한다. 켜진 스위치는 1, 꺼진 스위치는 0으로 표시하고, 스위치 상태 사이에 빈칸을 하나씩 둔다. 37 | 38 | 39 | --- 40 | 41 | ## 코드 42 | ### 1. 입력받기 43 | ```java 44 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 45 | StringTokenizer st = new StringTokenizer(br.readLine()); 46 | 47 | int n = Integer.parseInt(st.nextToken()); 48 | arr = new int[n]; 49 | 50 | st = new StringTokenizer(br.readLine()); 51 | // 스위치 상태 입력받기 52 | for(int i=0; i= arr.length || data-i < 0) { 97 | break; 98 | } 99 | if(arr[data+i] == arr[data-i]) { 100 | arr[data+i] = arr[data+i] == 1 ? 0 : 1; 101 | arr[data-i] = arr[data-i] == 1 ? 0 : 1; 102 | } else { 103 | return arr; 104 | } 105 | } 106 | return arr; 107 | } 108 | ``` 109 | 110 | ### 5. 출력 111 | *출력은 20글자 마다 줄바꿈을 한다. 112 | ```java 113 | int cnt = 1; 114 | // 출력 115 | for(int i=0; i 0 && i % 20 == 0) { 117 | System.out.println(); 118 | } 119 | System.out.println(); 120 | cnt++; 121 | } 122 | System.out.print(arr[i] +" "); 123 | } 124 | ``` 125 | -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Silver I/BoJ 1986/Baekjoon_1986.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.StringTokenizer; 5 | 6 | public class Baekjoon_1986 { 7 | static class Pos{ 8 | int x; 9 | int y; 10 | 11 | Pos(int x, int y){ 12 | this.x = x; 13 | this.y = y; 14 | } 15 | } 16 | 17 | public static int[] knight_dx = {-1,-2,-2,-1,1,2,2,1}; 18 | public static int[] knight_dy = {-2,-1,1,2,2,1,-1,-2}; 19 | 20 | public static int[] queen_dx = {0,1,1,1,0,-1,-1,-1}; 21 | public static int[] queen_dy = {1,1,0,-1,-1,-1,0,1}; 22 | 23 | public static void main(String[] args) throws IOException{ 24 | 25 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 26 | StringTokenizer st = new StringTokenizer(br.readLine()); 27 | int n = Integer.parseInt(st.nextToken()); 28 | int m = Integer.parseInt(st.nextToken()); 29 | 30 | int[][] map = new int[n + 1][m + 1]; 31 | 32 | st = new StringTokenizer(br.readLine()); 33 | int queenNum = Integer.parseInt(st.nextToken()); 34 | Pos[] queens = new Pos[queenNum]; 35 | for(int i = 0;i < queenNum;i++) { 36 | int y = Integer.parseInt(st.nextToken()); 37 | int x = Integer.parseInt(st.nextToken()); 38 | 39 | map[y][x] = 2; 40 | 41 | queens[i] = new Pos(x, y); 42 | } 43 | 44 | st = new StringTokenizer(br.readLine()); 45 | int knightNum = Integer.parseInt(st.nextToken()); 46 | Pos[] knights = new Pos[knightNum]; 47 | for(int i = 0;i < knightNum;i++) { 48 | int y = Integer.parseInt(st.nextToken()); 49 | int x = Integer.parseInt(st.nextToken()); 50 | 51 | map[y][x] = 2; 52 | 53 | knights[i] = new Pos(x, y); 54 | } 55 | 56 | st = new StringTokenizer(br.readLine()); 57 | int pawnNum = Integer.parseInt(st.nextToken()); 58 | Pos[] pawns = new Pos[pawnNum]; 59 | for(int i = 0;i < pawnNum;i++) { 60 | int y = Integer.parseInt(st.nextToken()); 61 | int x = Integer.parseInt(st.nextToken()); 62 | 63 | map[y][x] = 2; 64 | 65 | pawns[i] = new Pos(x, y); 66 | } 67 | 68 | // 퀸 동작 69 | for(int i = 0; i < queenNum;i++) { 70 | int queenX = queens[i].x; 71 | int queenY = queens[i].y; 72 | 73 | for(int j = 0; j < 8; j++) { 74 | int nowX = queenX; 75 | int nowY = queenY; 76 | while(true) { 77 | int nextX = nowX + queen_dx[j]; 78 | int nextY = nowY + queen_dy[j]; 79 | 80 | if(nextX < 1 || nextX > m || nextY < 1 || nextY > n) 81 | break; 82 | if(map[nextY][nextX] == 2) 83 | break; 84 | 85 | map[nextY][nextX] = 1; 86 | nowX = nextX; 87 | nowY = nextY; 88 | } 89 | } 90 | } 91 | 92 | // 나이트 동작 93 | for(int i = 0; i < knightNum;i++) { 94 | int knightX = knights[i].x; 95 | int knightY = knights[i].y; 96 | 97 | for(int j = 0; j < 8; j++) { 98 | int nextX = knightX + knight_dx[j]; 99 | int nextY = knightY + knight_dy[j]; 100 | 101 | if(nextX < 1 || nextX > m || nextY < 1 || nextY > n) 102 | continue; 103 | if(map[nextY][nextX] == 2) 104 | continue; 105 | 106 | map[nextY][nextX] = 1; 107 | } 108 | } 109 | 110 | /* 111 | for(int[] row : map) { 112 | System.out.println(Arrays.toString(row)); 113 | } 114 | */ 115 | 116 | int result = 0; 117 | for(int i = 1;i <= n; i++) { 118 | for(int j = 1; j <= m;j++) { 119 | if(map[i][j] == 0) 120 | result++; 121 | } 122 | } 123 | System.out.println(result); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Gold II/Boj 1167/README.md: -------------------------------------------------------------------------------- 1 | # [백준 1167 트리의 지름](https://www.acmicpc.net/problem/1167) 2 | 3 | solved.ac Gold II 4 | 5 | ## 카테고리 6 | 7 | 그래프 이론, 그래프 탐색, 트리, 깊이 우선 탐색 8 | 9 | ## 전체 코드 10 | 11 | ```java 12 | import java.io.BufferedReader; 13 | import java.io.IOException; 14 | import java.io.InputStreamReader; 15 | import java.util.*; 16 | 17 | 18 | public class Main { 19 | 20 | static int V; 21 | static ArrayList> graph = new ArrayList<>(); 22 | static boolean[] visit; 23 | static int max = Integer.MIN_VALUE; 24 | static int endPoint; 25 | 26 | public static void main(String[] args) throws IOException { 27 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 28 | StringBuilder sb = new StringBuilder(); 29 | StringTokenizer st; 30 | 31 | int V = Integer.parseInt(br.readLine()); 32 | for(int i = 0; i <= V; i++) { 33 | graph.add(new ArrayList<>()); 34 | } 35 | visit = new boolean[V + 1]; 36 | 37 | int u, v, cost; 38 | for(int i = 0; i < V; i++) { 39 | st = new StringTokenizer(br.readLine()); 40 | 41 | u = Integer.parseInt(st.nextToken()); 42 | while(true) { 43 | v = Integer.parseInt(st.nextToken()); 44 | if(v == -1) break; 45 | 46 | cost = Integer.parseInt(st.nextToken()); 47 | 48 | graph.get(u).add(new int[] {v, cost}); 49 | } 50 | } 51 | 52 | dfs(1, 0); 53 | 54 | max = Integer.MIN_VALUE; 55 | visit = new boolean[V + 1]; 56 | dfs(endPoint, 0); 57 | 58 | System.out.println(max); 59 | } 60 | 61 | static void dfs(int now, int dist) { 62 | if(visit[now]) return; 63 | 64 | visit[now] = true; 65 | 66 | for(int i = 0; i < graph.get(now).size(); i++) { 67 | if(!visit[graph.get(now).get(i)[0]]) { 68 | dfs(graph.get(now).get(i)[0], dist + graph.get(now).get(i)[1]); 69 | } 70 | } 71 | 72 | if(max < dist) { 73 | max = dist; 74 | endPoint = now; 75 | } 76 | } 77 | } 78 | 79 | ``` 80 | 81 | ## 시간복잡도 82 | 83 | 위 알고리즘은 dfs함수를 두 번 사용하도록 이루어져 있다. dfs의 시간복잡도는 O(V + E)를 가진다. 84 | 85 | 이 문제에서 트리 정점의 갯수 V의 최대 크기는 100,000이다. 86 | 87 | ## 풀이 88 | 89 | **⏱️소요시간 40분**
90 | 91 | 문제를 풀기 위해 떠올린 방법은 다음과 같다. 92 | 93 | 1. 루트 노드에서 가장 먼 노드를 찾는다. 94 | 2. 루트 노드에서 가장 먼 노드와 거리가 가장 먼 노드를 찾고 지름을 계산한다. 95 | 96 | 위 방법을 사용하기 위해서 문제에서 서술한 자료구조는 트리지만 양방향 그래프로 문제를 풀었다. 97 | 98 | "1." 에서 루트 노드에서 출발하여 가장 먼 노드를 구하였다. ⭐트리의 특성에 의해 임의의 한 정점에서 가장 먼 정점(Vertex A)으로 가는 경로와 그렇게 구한 정점(Vertex A)에서 가장 먼 정점 사이의 경로는 늘 일정부분 겹치게 된다. 99 | 100 | ![Alt text](ExampleTree.png) 101 | 102 | 위 트리의 지름은 노드 9노드 12를 연결하는 경로이다. 그럼 임의의 한 노드를 고르고 최장거리를 갖는 다른 노드를 구해보자. 103 | 104 | 7번 노드 : 7 -> 4 -> 2 -> 1 -> 3 -> 5 -> 9
105 | 2번 노드 : 2 -> 1 -> 3 -> 5 -> 9
106 | 6번 노드 : 6 -> 3 -> 5 -> 9
107 | 108 | 5번 노드 : 5 -> 3 -> 6 -> 12
109 | 10번 노드 : 10 -> 5 -> 3 -> 6 -> 12
110 | 111 | 위 예시처럼 임의의 한 노드를 고르고 가장 멀리 떨어진 노드를 구한다면 그 노드는 반드시 지름을 구성하는 두 노드 중 하나일 것이다. 112 | 113 | 따라서 굳이 루트노드를 고를 필요는 없다. 임의의 노드로 부터 가장 먼 노드를 구하기만 하면 된다. 114 | ```java 115 | dfs(1, 0); 116 | ``` 117 | ```java 118 | static void dfs(int now, int dist) { 119 | if(visit[now]) return; 120 | 121 | visit[now] = true; 122 | 123 | for(int i = 0; i < graph.get(now).size(); i++) { 124 | if(!visit[graph.get(now).get(i)[0]]) { 125 | dfs(graph.get(now).get(i)[0], dist + graph.get(now).get(i)[1]); 126 | } 127 | } 128 | 129 | if(max < dist) { 130 | max = dist; 131 | endPoint = now; // 지름을 구성하는 노드들 중 하나 기억 132 | } 133 | } 134 | ``` 135 | 136 | 위에서 구한 정점에서 dfs 탐색을 출발하여 가장 먼 거리에 위치한 노드까지의 거리가 지름임을 알 수 있다. 137 | ```java 138 | max = Integer.MIN_VALUE; 139 | visit = new boolean[V + 1]; 140 | dfs(endPoint, 0); 141 | ``` 142 | 143 | 144 | ## 결과 145 | 146 | 결과 : [맞았습니다!!](https://www.acmicpc.net/source/65139894)
147 | 메모리 : 106848 KB
148 | 시간 : 1176 ms
149 | 언어 : JAVA
150 | 코드길이 : 1492 B
151 | -------------------------------------------------------------------------------- /seoul_21_minjaekim/BoJ/Platinum IV/boj13907/README.md: -------------------------------------------------------------------------------- 1 | # [[Platinum IV] 세금 - 13907](https://www.acmicpc.net/problem/13907) 2 | 3 | ### 분류 4 | 5 | 데이크스트라, 다이나믹 프로그래밍, 그래프 이론 6 | 7 | ## 시간복잡도 8 | 9 | `O((V + E) log V) + O(n + m + k) + O(m) + O(k * (n log n + n))` 10 | 11 | ## 문제 설명 12 | 13 | 주언이는 경제학을 배워 행상인이 되었다. 두 도시를 오가며 장사를 하는데, 통행료의 합이 가장 적은 경로로 이동하려 한다. 도시들은 양방향 도로로 연결되어있으며, 도로마다 통행료가 존재한다. 14 | 15 | 그런데 정부는 세금 인상안을 발표하였다. 세금을 한 번에 올리면 문제가 발생할 수 있으므로 여러 단계에 걸쳐서 올린다고 한다. 세금이 `A`만큼 오르면 모든 도로의 통행료가 각각 `A`만큼 오르게 된다. 세금이 오르게 되면 주언이가 내야 하는 통행료가 변할 수 있다. 16 | 17 | 주언이를 도와 초기의 최소 통행료와 세금이 오를 때마다의 최소 통행료를 구하시오. 18 | 19 | ## 입력 20 | 21 | 첫 번째 줄에 세 정수 `N (2 ≤ N ≤ 1,000)`, `M (1 ≤ M ≤ 30,000)`, `K (0 ≤ K ≤ 30,000)`가 주어진다. 각각 도시의 수, 도로의 수, 세금 인상 횟수를 의미한다. 22 | 23 | 두 번째 줄에는 두 정수 `S와 D (1 ≤ S, D ≤ N, S ≠ D)`가 주어진다. 각각 `출발 도시`와 `도착 도시` 번호를 의미한다. 도시 번호는 `1`부터 시작한다. 24 | 25 | 다음 `M개의 줄`에는 각각 도로 정보를 나타내는 세 정수 `a, b (1 ≤ a < b ≤ N)`, `w (1 ≤ w ≤ 1,000)`가 주어진다. 도시 `a`와 도시 `b`가 통행료 `w`인 도로로 연결되어 있다는 것을 의미한다. 26 | 27 | 다음 총 `K개의 줄`에는 각각 정수 `p (1 ≤ p ≤ 10)`가 주어진다. 각각 `첫 번째, 두 번째, …, K 번째`에 인상되는 세금을 의미한다. 28 | 29 | `S`에서 `D`로 이동할 수 없는 경우는 주어지지 않는다. 30 | 31 | ## 출력 32 | 33 | `첫 번째 줄`에 `세금이 오르기 전`의 `최소 통행료`를 출력한다. 34 | 35 | `두 번째 줄`부터 `K개의 줄`에 각각 `첫 번째, 두 번째, …, K 번째` 세금이 올랐을 때의 `최소 통행료`를 출력한다. 36 | 37 | ## 해설 38 | 39 | 간선 구조체 40 | - to : 도착지 41 | - cost : 비용 42 | 43 | ```cpp 44 | struct Edge { 45 | int to; 46 | int cost; 47 | Edge(int to, int cost) : to(to), cost(cost) {} 48 | }; 49 | ``` 50 | 51 | 다익스트라 알고리즘에 사용하는 노드 구조체 52 | - id : 현재 노드 번호 53 | - dist : 현재 노드까지의 최소 비용 54 | - edge_count : 현재 노드까지의 최소 비용으로 도착한 간선의 개수 55 | 56 | ```cpp 57 | struct Node { 58 | int id; 59 | int dist; 60 | int edge_count; 61 | Node(int id, int dist, int edge_count) : id(id), dist(dist), edge_count(edge_count) {} 62 | }; 63 | ``` 64 | 65 | - graph : 간선 정보를 저장하는 벡터 66 | - dist : dist[i][j] : i번 노드까지 j개의 간선을 사용하여 도착하는 최소 비용 (DP 메모이제이션 배열) 67 | 68 | ```cpp 69 | vector graph[1000]; 70 | int dist[1001][1001]; 71 | ``` 72 | 73 | 다익스트라 알고리즘을 사용하여 각 노드의 소요 간선 별 최소 비용을 구한다. 74 | 75 | 다만 같은 노드라도 다른 간선의 개수로 도착하는 최소 비용이 다를 수 있으므로 전체 탐색을 해야 하기 때문에 정렬에 시간이 추가로 소요되는 priority queue가 아닌 일반 queue를 사용했다. 76 | 77 | ```cpp 78 | void dijkstra(int s, int e) { 79 | queue pq; 80 | pq.push(Node(s, 0, 0)); 81 | dist[s][0] = 0; 82 | while (!pq.empty()) { 83 | Node node = pq.front(); 84 | pq.pop(); 85 | if (node.dist > dist[node.id][node.edge_count]) continue; 86 | for (Edge edge : graph[node.id]) { 87 | int next_dist = node.dist + edge.cost; 88 | if (next_dist < dist[edge.to][node.edge_count + 1]) { 89 | dist[edge.to][node.edge_count + 1] = next_dist; 90 | pq.push({ edge.to, next_dist, node.edge_count + 1 }); 91 | } 92 | } 93 | } 94 | } 95 | ``` 96 | 97 | main 함수에서는 입력을 받고 다익스트라 알고리즘을 사용하여 최소 비용을 구한다. 98 | 99 | ```cpp 100 | int n, m, k, a, b; 101 | cin >> n >> m >> k >> a >> b; 102 | for (int i = 1; i <= n; i++) 103 | for (int j = 0; j < n; j++) 104 | dist[i][j] = numeric_limits::max(); 105 | for (int i = 0; i < m; ++i) 106 | { 107 | int f, t, c; 108 | cin >> f >> t >> c; 109 | graph[f].push_back(Edge(t, c)); 110 | graph[t].push_back(Edge(f, c)); 111 | } 112 | 113 | dijkstra(a, b); 114 | ``` 115 | 116 | 그리디 알고리즘을 사용하여 세금이 오르기 전의 최소 비용을 구한다. 117 | 118 | 이 과정에서 세금이 올라도 최소 비용이 될 수 없는 경우는 제외한다. 119 | 최소 비용과 간선의 개수가 둘 다 다른 경우보다 크다면 최소 비용이 될 수 없다. 120 | 121 | 기존의 배열은 간선의 개수가 작은 순으로 정렬되어 있으므로 최소 비용을 기준으로 선별한다. 122 | 123 | ```cpp 124 | vector> cand; 125 | int min_dist = dist[b][0]; 126 | for (int i = 1; i < n; ++i) { 127 | if (dist[b][i] < min_dist) { 128 | min_dist = dist[b][i]; 129 | cand.emplace_back(dist[b][i], i); 130 | } 131 | } 132 | sort(cand.begin(), cand.end()); 133 | cout << cand[0].first << '\n'; 134 | ``` 135 | 136 | 세금을 입력받아 최소 비용을 업데이트하고, 최소 비용을 기준으로 정렬 후, 간선의 개수를 기준으로 선별한다. 137 | 138 | ```cpp 139 | for (int i = 0; i < k; ++i) { 140 | int p; 141 | cin >> p; 142 | for (int j = 0; j < cand.size(); ++j) 143 | cand[j].first += p * cand[j].second; 144 | sort(cand.begin(), cand.end()); 145 | vector> new_cand; 146 | new_cand.push_back(cand[0]); 147 | int min_edge_count = cand[0].second; 148 | for (int j = 1; j < cand.size(); ++j) 149 | if (cand[j].second < min_edge_count) 150 | new_cand.push_back(cand[j]); 151 | cand = new_cand; 152 | cout << cand[0].first << '\n'; 153 | } 154 | ``` 155 | 156 | ## 성능 요약 157 | 158 | 메모리: 6892 KB, 시간: 252 ms 159 | 160 | 결과 : [맞았습니다!!](http://boj.kr/fa8291c7c7cb405aa982550262e37db4) -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Platinum V/Boj 3015/README.md: -------------------------------------------------------------------------------- 1 | # [백준 3015 오아시스 재결합](https://www.acmicpc.net/problem/3015) 2 | 3 | solved.ac Platinum V 4 | 5 | ## 카테고리 6 | 7 | 자료 구조, 스택 8 | 9 | ## 전체 코드 10 | 11 | ```java 12 | import java.io.BufferedReader; 13 | import java.io.IOException; 14 | import java.io.InputStreamReader; 15 | import java.util.Stack; 16 | 17 | public class Baekjoon_3015 { 18 | 19 | static class Man { 20 | int duplicate; 21 | int height; 22 | 23 | Man(int duplicate, int height) { 24 | this.duplicate = duplicate; 25 | this.height = height; 26 | } 27 | } 28 | 29 | public static void main(String[] args) throws IOException { 30 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 31 | int N = Integer.parseInt(br.readLine()); 32 | 33 | Stack stack = new Stack<>(); 34 | long result = 0; 35 | for(int i = 0;i < N; i++) { 36 | 37 | int height = Integer.parseInt(br.readLine()); 38 | int duplicate = 1; 39 | while(!stack.empty() && stack.peek().height <= height) { 40 | Man man = stack.pop(); 41 | result += man.duplicate; 42 | 43 | if(man.height == height) { 44 | duplicate += man.duplicate; 45 | } 46 | } 47 | 48 | if(!stack.isEmpty()) 49 | result++; 50 | 51 | stack.push(new Man(duplicate, height)); 52 | } 53 | 54 | System.out.println(result); 55 | } 56 | } 57 | 58 | ``` 59 | 60 | ## 시간복잡도 61 | 62 | 코드로는 시간복잡도 계산이 모호한 부분이 있어 논리적으로 시간복잡도를 계산했다. N명의 사람은 스택에 한번씩 push 되어서 최악의 경우 스택이 비워질 때까지 pop 하므로 작업의 총량은 2N이다. 63 | 64 | 즉, 시간복잡도는 **O(N)이다**. 65 | 66 | ## 풀이 67 | 68 | **⏱️소요시간 60분**
69 | 70 | N의 최대가 500,000이므로 O(N^2) 알고리즘은 무조건 시간초과가 터진다. 이 문제의 핵심은 필요한 성질을 논리적으로 파악하고 이를 스택 자료구조를 이용하여 최적의 계산을 통해 결과값으로 찾아내는 것이다. 71 | 72 | 문제는 대표적인 스택 자료구조 활용 문제인 [탑](https://www.acmicpc.net/problem/2493)과 비슷하다.
두 사람 사이에 서로의 키보다 큰 사람이 없다면 두 사람은 서로를 바라 볼 수 있다. 모든 사람들의 키가 주어졌을 대, 서로를 볼 수 있는 쌍의 수를 구하면 된다. '탑' 문제를 기억하는 사람은 금방 이 문제가 스택을 활용한 문제라는 것을 알 수 있다. 73 | 74 | 문제를 푸는 원칙은 다음과 같다. 75 | 76 | 줄의 왼쪽부터 사람의 키를 확인하면서 스택에 집어 넣을 것이다. 77 | 78 | ⭐⭐이 때, 본인의 왼쪽만을 바라보며 결과를 저장한다!!!⭐⭐ 79 | 80 | |1|2|3|4|5| 81 | |:------:|:---:|:---:|:---:|:---:| 82 | |1|2|7|4|9| 83 | 84 | 1번 사람부터 키를 확인하면 1이 왼쪽에서 볼 수 있는 사람은 아무도 없다.
85 | 2번 사람의 키를 확인했을 때 본인의 왼쪽에서 볼 수 있는 사람은 1뿐이다.
86 | 3번 사람의 키를 확인했을 때 본인의 왼쪽에서 볼 수 있는 사람은 2뿐이다.
87 | 4번 사람의 키를 확인했을 때 본인의 왼쪽에서 볼 수 있는 사람은 3뿐이다.
88 | 5번 사람의 키를 확인했을 때 본인의 왼쪽에서 볼 수 있는 사람은 3, 4뿐이다.
89 | 90 | 만약 스택의 top에 있는 사람이 본인의 키보다 작거나 같다면 스택의 top을 pop()한다. 이 동작을 스택의 top이 본인보다 키가 클 때까지 혹은 스택이 빌 때까지 반복한다. pop을 수행하면 볼 수 있는 사람 쌍을 1씩 증가시킨다. 91 | 92 | 본인을 stack에 추가하기 전에 만약 stack이 비어있지 않다면 stack의 탑과 바로 마주볼 수 있는 상황을 포함하기 위하여 사람 쌍을 1 증가시킨다. 그 후 본인을 stack에 push한다. 93 | 94 | ```java 95 | while(!stack.empty() && stack.peek() <= height) { 96 | stack.pop(); 97 | result++; 98 | } 99 | 100 | if(!stack.isEmpty()) 101 | result++; 102 | 103 | stack.push(height); 104 | ``` 105 | 106 | 여기까지의 흐름은 탑과 거의 유사하게 흘러왔지만 '서로의 키보다 큰 사람이 없다면' 이라는 조건이 말썽이다. 키가 같은 사람이 생길 상황을 예외적인 케이스로 고려해주어야 한다. 107 | 108 | |1|2|3|4|5|6|7| 109 | |:------:|:---:|:---:|:---:|:---:|:---:|:---:| 110 | |1|2|7|4|4|4|9| 111 | 112 | 위 상황에서 예외적인 케이스만 살펴보자. 113 | 114 | 4번 사람은 이전과 동일하게 3번만 볼 수 있다.
115 | 5번 사람은 3, 4번을 볼 수 있다.
116 | 6번 사람은 3, 4, 5번을 볼 수 있다.
117 | 7번 사람은 3, 4, 5, 6번을 볼 수 있다. 118 | 119 | 즉, 키가 같은 사람이 몇번 나오는지 중복 갯수 체크가 함께 이루어져야 한다. 120 | 이를 위해 새로운 사람 객체를 만들었다. 121 | ```java 122 | static class Man { 123 | int duplicate; 124 | int height; 125 | 126 | Man(int duplicate, int height) { 127 | this.duplicate = duplicate; 128 | this.height = height; 129 | } 130 | } 131 | ``` 132 | 위 객체의 duplicate를 통해서 같은 키 중복이 몇번 연속적으로 일어났는지 확인하는 코드는 다음과 같다. 133 | 134 | ```java 135 | int height = Integer.parseInt(br.readLine()); 136 | int duplicate = 1; 137 | while(!stack.empty() && stack.peek().height <= height) { 138 | Man man = stack.pop(); 139 | result += man.duplicate; 140 | 141 | if(man.height == height) { 142 | duplicate += man.duplicate; 143 | } 144 | } 145 | 146 | if(!stack.isEmpty()) 147 | result++; 148 | 149 | stack.push(new Man(duplicate, height)); 150 | ``` 151 | 152 | ## 결과 153 | 154 | 결과 : [맞았습니다!!](https://www.acmicpc.net/source/64137478)
155 | 메모리 : 59576 KB
156 | 시간 : 428 ms
157 | 언어 : JAVA
158 | 코드길이 : 1046 B
159 | -------------------------------------------------------------------------------- /seoul_21_minjaekim/MinCoding/Algorithm Tower/Dijkstra Tower/6/README.md: -------------------------------------------------------------------------------- 1 | # [알고리즘 탑] Dijkstra의 탑 6번 - 무서운 시어머니 2 | 3 | ## 카테고리 4 | 5 | `Dijkstra` 6 | 7 | ## 시간복잡도 8 | 9 | `O(n^2 * log n)` 10 | 11 | ## 풀이 12 | 13 | ### 처음 풀었던 풀이 14 | 15 | 전형적인 다익스트라 알고리즘을 이용해 전체 좌표에 대한 최단 거리를 전부 구한 상태에서, 최대 거리를 찾는다. 16 | 17 | ```cpp 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #define MAX_SIZE 1000 24 | 25 | using namespace std; 26 | 27 | int map[MAX_SIZE][MAX_SIZE]; 28 | int dist[MAX_SIZE][MAX_SIZE]; 29 | pair directions[4] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; 30 | 31 | int dijkstra(pair start = {0, 0}, int map_size = MAX_SIZE) { 32 | priority_queue>, vector>>, greater<>> pq; 33 | pq.emplace(map[start.second][start.first], start); 34 | dist[start.second][start.first] = map[start.second][start.first]; 35 | 36 | while(!pq.empty()) { 37 | auto [cost, pos] = pq.top(); 38 | auto [cur_x, cur_y] = pos; 39 | pq.pop(); 40 | 41 | if (dist[cur_y][cur_x] < cost) continue; 42 | 43 | for (auto [dx, dy] : directions) { 44 | int next_x = cur_x + dx; 45 | int next_y = cur_y + dy; 46 | 47 | if (next_x < 0 || next_x >= map_size || next_y < 0 || next_y >= map_size || map[next_y][next_x] == -1) continue; 48 | 49 | int next_cost = cost + map[next_y][next_x]; 50 | if (dist[next_y][next_x] > next_cost) { 51 | dist[next_y][next_x] = next_cost; 52 | pq.emplace(next_cost, make_pair(next_x, next_y)); 53 | } 54 | } 55 | } 56 | 57 | int max_dist = 0; 58 | for (int i = 0; i < map_size; ++i) 59 | for (int j = 0; j < map_size; ++j) 60 | max_dist = max(max_dist, dist[i][j]); 61 | 62 | return max_dist; 63 | } 64 | 65 | int main() 66 | { 67 | ios_base::sync_with_stdio(false); 68 | cin.tie(nullptr); 69 | cout.tie(nullptr); 70 | 71 | int y, x, n; 72 | cin >> y >> x >> n; 73 | for (int i = 0; i < n; ++i) { 74 | for (int j = 0; j < n; ++j) { 75 | cin >> map[i][j]; 76 | if (map[i][j] != -1) 77 | dist[i][j] = numeric_limits::max(); 78 | } 79 | } 80 | 81 | cout << dijkstra({x, y}, n) << '\n'; 82 | 83 | return 0; 84 | } 85 | ``` 86 | 87 | ### 개선한 풀이 88 | 89 | > 일반적인 그래프 상황에서 다익스트라 알고리즘을 적용하는 상황과는 다르게, 이 문제에서는 간선이 아닌 노드가 스스로 가중치를 가지고 있다. 90 | > 91 | > 때문에 득정 노드로 들어가는 모든 간선은 같은 가중치를 가지고 있으므로, 특정 노드에 대한 최단 경로는 해당 노드 직전 노드들의 누적 가중치 중 가장 작은 값을 가진 노드가 된다. 92 | > 93 | > 특정 노드에 인접한 노드들은 `priority queue`에 의해 정렬되므로, 특정 노드에 가장 처음 도달한 노드를 통하는 경로가 최단 경로임을 보장할 수 있다. 94 | > 95 | > 이 부분은 특정 노드에 도달하기 직전 노드들에도 똑같이 적용이 가능하며, 이를 이용해 귀납적으로 모든 노드에 대하여 가장 먼저 방문하는 경로가 최단 경로임을 보장할 수 있다. 96 | 97 | 일반적으로 간선에 가중치가 있는 상황을 가정해보자. 98 | ``` 99 | A-1-B 100 | | | 101 | 2 100 102 | | | 103 | C-3-D 104 | ``` 105 | 위와 같은 상황에서 `A`노드에서 `B`노드로의 최소거리를 `다익스트라 알고리즘`으로 구하게 된다면, 첫 번째 단계에서의 `pq`는 `B, C` 의 우선순위를 가지게 된다. 106 | 이로 인해 D 노드에 가장 먼저 방문하는 경로는 `A-B-C`의 `101`거리의 경로가 되고 이는 `A-C-D`의 `5`거리의 경로보다 긴 거리다. 107 | 108 | 이와 같은 상황때문에 `다익스트라 알고리즘`은 `BFS`와는 다르게 가장 먼저 방문한 경로의 거리가 최소 거리라고 보장하지 못하고 목표 노드로 도착할 수 있는 모든 경로를 탐색한 뒤에 더이상 목표 노드로 가는 더 작은 경로가 없을때에서야 최소 경로를 보장할 수 있디. 109 | 110 | 그러나 해당 문제와 같이 노드 자체에 가중치가 있다면 각 노드로 들어가는 모든 간선은 같은 가중치를 가지게 된다. 111 | 112 | ``` 113 | A--1--B 114 | | | 115 | 2 100 116 | | | 117 | C-100-D 118 | ``` 119 | 120 | 위와 같은 조건 하에는 `D`노드로 들어가는 최소 경로는 `B`노드의 최소경로와 `C`노드의 최소 경로의 우선순위와 동일함을 보장할 수 있게 되고, 이를 귀납적으로 축소해 보면 각 노드에 도착하는 첫번째 경로가 해당 노드로의 최소 경로임이 보장되게 되어서 첫번째 경로 이후로 추가적인 탐색이 필요없다는 결론에 도달하게 된다. 121 | 122 | 최단 경로를 구하기 위한 순서 정렬을 위해 priority queue를 오름차순으로 정렬하도록 한 뒤, 시작 노드를 넣어준다. 123 | 124 | ```cpp 125 | priority_queue>, vector>>, greater<>> pq; 126 | pq.emplace(map[start.second][start.first], start); 127 | visited[start.second][start.first] = true; 128 | ``` 129 | 130 | 조건에 맞는 탐색할 노드가 없어질때까지, 다음과 같은 과정을 반복한다. 131 | 132 | 1. 우선순위 큐에서 가장 작은 경로를 가진 노드를 꺼낸다. 133 | 2. 해당 노드에 인접한(위, 아래, 좌, 우) 노드들 중 방문하지 않은 노드를 해당 노드로 이동하는 가중치를 더해서 우선순위 큐에 넣어주고, 해당 노드를 방문한 것으로 체크한다. 134 | 3. 방문하지 않은 노드라는 의미는 현재 경로가 해당 노드에 방문이 가능한 최단 경로라는 의미이므로, 이전에 저장해뒀던 최대 거리와 현재 경로로 해당 노드에 방문이 가능한 거리를 비교해 최대 거리를 갱신해준다. 135 | 136 | ```cpp 137 | while (!pq.empty()) { 138 | auto [cost, pos] = pq.top(); 139 | auto [cur_x, cur_y] = pos; 140 | pq.pop(); 141 | 142 | for (auto [dx, dy] : directions) { 143 | int next_x = cur_x + dx; 144 | int next_y = cur_y + dy; 145 | 146 | if (next_x < 0 || next_x >= map_size || next_y < 0 || next_y >= map_size || map[next_y][next_x] == -1) continue; 147 | 148 | if (!visited[next_y][next_x]) { 149 | int next_cost = cost + map[next_y][next_x]; 150 | max_dist = max(max_dist, next_cost); 151 | visited[next_y][next_x] = true; 152 | pq.emplace(next_cost, make_pair(next_x, next_y)); 153 | } 154 | } 155 | } 156 | ``` 157 | 158 | ## 성능 요약 159 | 160 | 메모리: 2 MB, 시간: 0 ms 161 | -------------------------------------------------------------------------------- /seoul_10_parkhoje/boj15683/README.md: -------------------------------------------------------------------------------- 1 | # [Gold IV] 감시 - 15683 2 | 3 | [문제 링크](https://www.acmicpc.net/problem/15683) 4 | 5 | ### 성능 요약 6 | 7 | 메모리: 38476 KB, 시간: 356 ms 8 | 9 | ### 분류 10 | 11 | 백트래킹, 브루트포스 알고리즘, 구현, 시뮬레이션 12 | 13 | ### 문제 설명 14 | 15 |

스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감시할 수 있는 방법은 다음과 같다.

16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
1번2번3번4번5번
35 | 36 |

1번 CCTV는 한 쪽 방향만 감시할 수 있다. 2번과 3번은 두 방향을 감시할 수 있는데, 2번은 감시하는 방향이 서로 반대방향이어야 하고, 3번은 직각 방향이어야 한다. 4번은 세 방향, 5번은 네 방향을 감시할 수 있다.

37 | 38 |

CCTV는 감시할 수 있는 방향에 있는 칸 전체를 감시할 수 있다. 사무실에는 벽이 있는데, CCTV는 벽을 통과할 수 없다. CCTV가 감시할 수 없는 영역은 사각지대라고 한다.

39 | 40 |

CCTV는 회전시킬 수 있는데, 회전은 항상 90도 방향으로 해야 하며, 감시하려고 하는 방향이 가로 또는 세로 방향이어야 한다.

41 | 42 |
0 0 0 0 0 0
 43 | 0 0 0 0 0 0
 44 | 0 0 1 0 6 0
 45 | 0 0 0 0 0 0
46 | 47 |

지도에서 0은 빈 칸, 6은 벽, 1~5는 CCTV의 번호이다. 위의 예시에서 1번의 방향에 따라 감시할 수 있는 영역을 '#'로 나타내면 아래와 같다.

48 | 49 | 50 | 51 | 52 | 58 | 64 | 70 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 |
53 |
0 0 0 0 0 0
 54 | 0 0 0 0 0 0
 55 | 0 0 1 # 6 0
 56 | 0 0 0 0 0 0
57 |
59 |
0 0 0 0 0 0
 60 | 0 0 0 0 0 0
 61 | # # 1 0 6 0
 62 | 0 0 0 0 0 0
63 |
65 |
0 0 # 0 0 0
 66 | 0 0 # 0 0 0
 67 | 0 0 1 0 6 0
 68 | 0 0 0 0 0 0
69 |
71 |
0 0 0 0 0 0
 72 | 0 0 0 0 0 0
 73 | 0 0 1 0 6 0
 74 | 0 0 # 0 0 0
75 |
85 | 86 |

CCTV는 벽을 통과할 수 없기 때문에, 1번이 → 방향을 감시하고 있을 때는 6의 오른쪽에 있는 칸을 감시할 수 없다.

87 | 88 |
0 0 0 0 0 0
 89 | 0 2 0 0 0 0
 90 | 0 0 0 0 6 0
 91 | 0 6 0 0 2 0
 92 | 0 0 0 0 0 0
 93 | 0 0 0 0 0 5
94 | 95 |

위의 예시에서 감시할 수 있는 방향을 알아보면 아래와 같다.

96 | 97 | 98 | 99 | 100 | 108 | 116 | 124 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 |
101 |
0 0 0 0 0 #
102 | # 2 # # # #
103 | 0 0 0 0 6 #
104 | 0 6 # # 2 #
105 | 0 0 0 0 0 #
106 | # # # # # 5
107 |
109 |
0 0 0 0 0 #
110 | # 2 # # # #
111 | 0 0 0 0 6 #
112 | 0 6 0 0 2 #
113 | 0 0 0 0 # #
114 | # # # # # 5
115 |
117 |
0 # 0 0 0 #
118 | 0 2 0 0 0 #
119 | 0 # 0 0 6 #
120 | 0 6 # # 2 #
121 | 0 0 0 0 0 #
122 | # # # # # 5
123 |
125 |
0 # 0 0 0 #
126 | 0 2 0 0 0 #
127 | 0 # 0 0 6 #
128 | 0 6 0 0 2 #
129 | 0 0 0 0 # #
130 | # # # # # 5
131 |
왼쪽 상단 2: ↔, 오른쪽 하단 2: ↔왼쪽 상단 2: ↔, 오른쪽 하단 2: ↕왼쪽 상단 2: ↕, 오른쪽 하단 2: ↔왼쪽 상단 2: ↕, 오른쪽 하단 2: ↕
141 | 142 |

CCTV는 CCTV를 통과할 수 있다. 아래 예시를 보자.

143 | 144 |
0 0 2 0 3
145 | 0 6 0 0 0
146 | 0 0 6 6 0
147 | 0 0 0 0 0
148 | 
149 | 150 |

위와 같은 경우에 2의 방향이 ↕ 3의 방향이 ←와 ↓인 경우 감시받는 영역은 다음과 같다.

151 | 152 |
# # 2 # 3
153 | 0 6 # 0 #
154 | 0 0 6 6 #
155 | 0 0 0 0 #
156 | 
157 | 158 |

사무실의 크기와 상태, 그리고 CCTV의 정보가 주어졌을 때, CCTV의 방향을 적절히 정해서, 사각 지대의 최소 크기를 구하는 프로그램을 작성하시오.

159 | 160 | ### 입력 161 | 162 |

첫째 줄에 사무실의 세로 크기 N과 가로 크기 M이 주어진다. (1 ≤ N, M ≤ 8)

163 | 164 |

둘째 줄부터 N개의 줄에는 사무실 각 칸의 정보가 주어진다. 0은 빈 칸, 6은 벽, 1~5는 CCTV를 나타내고, 문제에서 설명한 CCTV의 종류이다.

165 | 166 |

CCTV의 최대 개수는 8개를 넘지 않는다.

167 | 168 | ### 출력 169 | 170 |

첫째 줄에 사각 지대의 최소 크기를 출력한다.

171 | -------------------------------------------------------------------------------- /seoul_11_hongyungi/BoJ/Gold III/Boj 2206/README.md: -------------------------------------------------------------------------------- 1 | # [백준 2206 벽 부수고 이동하기](https://www.acmicpc.net/problem/2206) 2 | 3 | solved.ac Gold III 4 | 5 | ## 카테고리 6 | 7 | 그래프 이론, 그래프 탐색, 너비 우선 탐색(bfs) 8 | 9 | ## 전체 코드 10 | 11 | ```java 12 | import java.io.BufferedReader; 13 | import java.io.IOException; 14 | import java.io.InputStreamReader; 15 | import java.util.*; 16 | 17 | public class Main { 18 | 19 | static int[][] map, visit; 20 | static int[] dx = {0,0,1,-1}; 21 | static int[] dy = {1,-1,0,0}; 22 | static int N, M; 23 | 24 | static int result = Integer.MAX_VALUE; 25 | 26 | static class Pos { 27 | int x; 28 | int y; 29 | int dis; 30 | int smash; 31 | 32 | Pos(int x, int y, int dis, int smash) { 33 | this.x = x; 34 | this.y = y; 35 | this.dis = dis; 36 | this.smash = smash; 37 | } 38 | } 39 | 40 | public static void main(String[] args) throws IOException { 41 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 42 | StringTokenizer st = new StringTokenizer(br.readLine()); 43 | 44 | int N = Integer.parseInt(st.nextToken()); 45 | int M = Integer.parseInt(st.nextToken()); 46 | 47 | map = new int[N + 1][M + 1]; 48 | visit = new int[N + 1][M + 1]; 49 | for(int i = 1; i <= N; i++) { 50 | String line = br.readLine(); 51 | 52 | for(int j = 1; j <= M; j++) { 53 | map[i][j] = Integer.parseInt(String.valueOf(line.charAt(j - 1))); 54 | } 55 | Arrays.fill(visit[i], Integer.MAX_VALUE); 56 | } 57 | 58 | Queue q = new LinkedList<>(); 59 | q.add(new Pos(1,1,1,0)); 60 | visit[1][1] = 0; 61 | 62 | while(!q.isEmpty()) { 63 | Pos now = q.poll(); 64 | 65 | if(now.x == M && now.y == N) { 66 | System.out.println(now.dis); 67 | return; 68 | } 69 | 70 | for(int i = 0; i < 4; i++) { 71 | int nextX = now.x + dx[i]; 72 | int nextY = now.y + dy[i]; 73 | 74 | if(nextX <= 0 || nextY <= 0 || nextX > M || nextY > N) 75 | continue; 76 | 77 | if(visit[nextY][nextX] > now.smash) { 78 | if(now.smash == 0 && map[nextY][nextX] == 1) { 79 | q.add(new Pos(nextX, nextY, now.dis + 1, 1)); 80 | visit[nextY][nextX] = 1; 81 | } else if(map[nextY][nextX] == 0) { 82 | q.add(new Pos(nextX, nextY, now.dis + 1, now.smash)); 83 | visit[nextY][nextX] = now.smash; 84 | } 85 | } 86 | } 87 | } 88 | 89 | System.out.println(-1); 90 | } 91 | } 92 | ``` 93 | 94 | ## 시간복잡도 95 | 96 | N X M 행렬 맵에서 BFS를 통해 (1, 1)부터 (N, M)까지 가는 최단 거리를 구하므로 시간복잡도는 O(N X M)이다. 97 | 98 | ## 풀이 99 | 100 | **⏱️소요시간 60분 이상**
101 | 102 | 가중치가 없는 행렬 맵에서 최단거리를 구해야 하므로 공식처럼 BFS 알고리즘을 꺼내게 된다. 하지만 일반적인 BFS와는 다르게 방문체크를 위한 boolean 타입의 2차원 배열을 사용할 수 없다. 103 | 104 | 문제에서는 단순히 '방문을 했다, 방문하지 않았다'라는 `두가지 상태`로 모든 경우의 수를 표현할 수 없다. '아직 한번도 방문을 하지 않았는가, 또는 벽을 한번도 부순적 없는 채로 방문하였는가, 또는 벽을 한번 부순채로 방문하였는가'라는 `세가지 상태`를 표현하여야 한다. 때문에 true of false로는 구분이 불가능하다. 105 | 106 | 따라서 선택할 수 있는 경우는 두가지이다.
107 | 1. 기존에 boolean 타입 2차원 배열로 체크하던 방문체크를 int 타입으로 바꿔 다양한 표현을 가능하게 할 수 있다. 108 | 2. boolean 타입 2차원 배열을 한 차원 늘려 3차원으로 선언한 후 더 다양한 표현을 가능하게 할 수 있다. 109 | 110 | 이번 문제에서는 1번 방법을 활용하여 풀었지만 코드를 직관적으로 이해하는 것은 2번 방법이 더 효율적인 것 같다. 111 | 112 | 현재 움직이고 있는 위치의 상태를 저장하기 위한 클래스를 선언한다. 우리는 이 Pos 클래스를 Queue에 넣고 빼며 BFS를 돌릴 것이다. 현재 위치에서 (1, 1)까지 떨어진 거리를 기억하기 위해 `int dis`를, 벽을 부순적 있는지 없는지를 기억하기 위해 `int smash`를 멤버 변수로 사용한다. 113 | ```java 114 | static class Pos { 115 | int x; 116 | int y; 117 | int dis; // (1, 1)까지의 거리이다. 118 | int smash; // 벽을 부순 적 있으면 1, 없으면 0이다. 119 | 120 | Pos(int x, int y, int dis, int smash) { 121 | this.x = x; 122 | this.y = y; 123 | this.dis = dis; 124 | this.smash = smash; 125 | } 126 | } 127 | ``` 128 | 129 | 코드에서는 한번도 방문하지 않은 상태를 Integer.MAX_VALUE로 표현한다. 또한 벽을 부수게 되면 visit의 값은 1이 되고 다음 Queue에서 꺼내졌을 때 visit에 해당 상태를 그대로 건내주게 된다. 130 | ```java 131 | /** 132 | * 반복문 내에서 133 | */ 134 | Arrays.fill(visit[i], Integer.MAX_VALUE); 135 | 136 | /** 137 | * BFS 내에서 138 | */ 139 | if(now.smash == 0 && map[nextY][nextX] == 1) { 140 | q.add(new Pos(nextX, nextY, now.dis + 1, 1)); 141 | visit[nextY][nextX] = 1; // 벽을 부수므로 상태가 1이 된다. 142 | } else if(map[nextY][nextX] == 0) { 143 | q.add(new Pos(nextX, nextY, now.dis + 1, now.smash)); 144 | visit[nextY][nextX] = now.smash; // 상태를 그대로 건내 준다. 145 | } 146 | ``` 147 | 148 | BFS의 조건에서 몇가지 주의할 점이 있다.
149 | 1. 방문 상태가 0인데(벽을 안부수고 방문했는데) smash상태가 1인 점은 갈 수 없다. <- 최단거리로 가려고 벽을 부수는데 충분히 0이 갈 수 있는 점이면 의미가 없는 행동이다. 150 | 2. 같은 상태가 방문한 점은 또 방문할 수 없다. 151 | 3. 방문 상태가 1이고 smash 상태가 0이면 1과 같은 이유로 방문 상태를 0으로 바꿔야 한다. 152 | 153 | 위 모든 조건을 만족하기 위한 BFS 조건은 아래처럼 간단하게 표현된다. 154 | 155 | ```java 156 | if(visit[nextY][nextX] > now.smash) { 157 | if(now.smash == 0 && map[nextY][nextX] == 1) { 158 | q.add(new Pos(nextX, nextY, now.dis + 1, 1)); 159 | visit[nextY][nextX] = 1; 160 | } else if(map[nextY][nextX] == 0) { 161 | q.add(new Pos(nextX, nextY, now.dis + 1, now.smash)); 162 | visit[nextY][nextX] = now.smash; 163 | } 164 | } 165 | ``` 166 | ## 결과 167 | 168 | 결과 : [맞았습니다!!](https://www.acmicpc.net/source/65045417)
169 | 메모리 : 172188 KB
170 | 시간 : 588 ms
171 | 언어 : JAVA
172 | 코드길이 : 1850 B
173 | -------------------------------------------------------------------------------- /seoul_09_kyoohyunkim/BOJ/Gold I/boj 17114/Boj_17114.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | import java.util.*; 3 | 4 | public class Main { 5 | static PScanner sc = new PScanner(System.in); 6 | static StringBuilder sb = new StringBuilder(); 7 | 8 | static StringTokenizer st; 9 | static int[][][][][][][][][][][] map; // 전체 맵입니다. 10 | static int nOfTomatos = 0; // 정상적인 토마토의 수입니다. 11 | 12 | static Queue queue; // bfs를 위한 queue입니다. 13 | static final int BLOCK = -1; 14 | 15 | static int m; 16 | static int n; 17 | static int o; 18 | static int p; 19 | static int q; 20 | static int r; 21 | static int s; 22 | static int t; 23 | static int u; 24 | static int v; 25 | static int w; 26 | 27 | // 22방향 이동 탐색 28 | static int[][] deltas = { 29 | {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 30 | {-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 31 | {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 32 | {0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 33 | {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, 34 | {0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0}, 35 | {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, 36 | {0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0}, 37 | {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, 38 | {0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0}, 39 | {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, 40 | {0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0}, 41 | {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, 42 | {0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0}, 43 | {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, 44 | {0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0}, 45 | {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, 46 | {0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0}, 47 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, 48 | {0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0}, 49 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 50 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, 51 | }; 52 | 53 | public static void main(String[] args) throws Exception { 54 | 55 | m = sc.nextInt(); 56 | n = sc.nextInt(); 57 | o = sc.nextInt(); 58 | p = sc.nextInt(); 59 | q = sc.nextInt(); 60 | r = sc.nextInt(); 61 | s = sc.nextInt(); 62 | t = sc.nextInt(); 63 | u = sc.nextInt(); 64 | v = sc.nextInt(); 65 | w = sc.nextInt(); 66 | map = new int[w][v][u][t][s][r][q][p][o][n][m]; // 맵의 크기를 받습니다. 해당 부분에서 유의해서 넣어줘야합니다. 67 | 68 | queue = new ArrayDeque<>(); 69 | // 입력을 받습니다. 70 | for (int ww = 0; ww < w; ww++) { 71 | for (int vv = 0; vv < v; vv++) { 72 | for (int uu = 0; uu < u; uu++) { 73 | for (int tt = 0; tt < t; tt++) { 74 | for (int ss = 0; ss < s; ss++) { 75 | for (int rr = 0; rr < r; rr++) { 76 | for (int qq = 0; qq < q; qq++) { 77 | for (int pp = 0; pp < p; pp++) { 78 | for (int oo = 0; oo < o; oo++) { 79 | for (int nn = 0; nn < n; nn++) { 80 | for (int mm = 0; mm < m; mm++) { 81 | int number = sc.nextInt(); 82 | if (number == 1) { 83 | queue.add(new RottenTomato(ww, vv, uu, tt, ss, rr, qq, pp, oo, nn, mm)); 84 | number = -1; 85 | } else if (number == 0) { 86 | nOfTomatos++; 87 | } 88 | map[ww][vv][uu][tt][ss][rr][qq][pp][oo][nn][mm] = number; 89 | } 90 | } 91 | } 92 | } 93 | } 94 | } 95 | } 96 | } 97 | } 98 | } 99 | } 100 | 101 | // 만약 시작부터 정상 토마토가 없다면 0 을 출력합니다. 102 | if (nOfTomatos == 0) { 103 | System.out.println(0); 104 | return; 105 | } 106 | 107 | // bfs를 돌면서 토마토를 처리합니다. 108 | int days = bfs(); 109 | if (nOfTomatos == 0) { // 정상 토마토가 0개가 되었다면 처리하는데 필요한 days를 작성합니다. 110 | System.out.println(days); 111 | } else // 모두 처리하지 못했다면 -1을 출력합니다. 112 | System.out.println(-1); 113 | 114 | 115 | } 116 | 117 | private static int bfs() { 118 | int days = 0; 119 | loop : while (!queue.isEmpty()) { 120 | int size = queue.size(); 121 | days++; // 바깥 반복이 시작될 때, 기간을 추가해줍니다. 122 | // 같은 너비에 있는 애들을 지웁니다. 123 | while (size-- > 0) { 124 | RottenTomato tomato = queue.poll(); 125 | for (int[] d : deltas) { 126 | int nw = tomato.w + d[0]; 127 | int nv = tomato.v + d[1]; 128 | int nu = tomato.u + d[2]; 129 | int nt = tomato.t + d[3]; 130 | int ns = tomato.s + d[4]; 131 | int nr = tomato.r + d[5]; 132 | int nq = tomato.q + d[6]; 133 | int np = tomato.p + d[7]; 134 | int no = tomato.o + d[8]; 135 | int nn = tomato.n + d[9]; 136 | int nm = tomato.m + d[10]; 137 | 138 | if (isIn(nw, nv, nu, nt, ns, nr, nq, np, no, nn, nm)) { 139 | queue.add(new RottenTomato(nw, nv, nu, nt, ns, nr, nq, np, no, nn, nm)); 140 | map[nw][nv][nu][nt][ns][nr][nq][np][no][nn][nm] = BLOCK; 141 | if (--nOfTomatos == 0) { // 만약 모든 토마토가 사라졌다면 종료합니다. 특히 반복이 많기 때문에, 해당 부분에서 종료해서 최적화를 해주어야 합니다. 142 | break loop; 143 | } 144 | } 145 | } 146 | } 147 | } 148 | return days; 149 | } 150 | 151 | // 해당 방향으로 이동 가능한지 체크하는 코드 152 | private static boolean isIn(int ww, int vv, int uu, int tt, int ss, int rr, int qq, int pp, int oo, int nn, int mm) { 153 | return ww >= 0 && ww < w && 154 | vv >= 0 && vv < v && 155 | uu >= 0 && uu < u && 156 | tt >= 0 && tt < t && 157 | ss >= 0 && ss < s && 158 | rr >= 0 && rr < r && 159 | qq >= 0 && qq < q && 160 | pp >= 0 && pp < p && 161 | oo >= 0 && oo < o && 162 | nn >= 0 && nn < n && 163 | mm >= 0 && mm < m && map[ww][vv][uu][tt][ss][rr][qq][pp][oo][nn][mm] == 0; 164 | } 165 | // Queue에서 사용할 토마토의 좌표 정보 166 | private static class RottenTomato { 167 | int w; 168 | int v; 169 | int u; 170 | int t; 171 | int s; 172 | int r; 173 | int q; 174 | int p; 175 | int o; 176 | int n; 177 | int m; 178 | 179 | public RottenTomato(int w, int v, int u, int t, int s, int r, int q, int p, int o, int n, int m) { 180 | this.w = w; 181 | this.v = v; 182 | this.u = u; 183 | this.t = t; 184 | this.s = s; 185 | this.r = r; 186 | this.q = q; 187 | this.p = p; 188 | this.o = o; 189 | this.n = n; 190 | this.m = m; 191 | } 192 | 193 | } 194 | // 입력 최적화 클래스 195 | static class PScanner{private final InputStreamReader in;private final char[]buf;private int len,ptr;public PScanner(InputStream input){in=new InputStreamReader(input);buf=new char[8192];}public boolean hasNext(){consume();return ptr' ';}public String next(){consume();char[]cbuf=new char[16];char clen=0;while((cbuf[clen++]=read())>' '){if(clen==cbuf.length)cbuf=Arrays.copyOf(cbuf,clen << 2);}return new String(cbuf,0,clen - 1);}public int nextInt(){consume();int v=0;char c=read();boolean neg=c=='-';if(neg)c=read();do{v=v * 10+c - '0';}while('0'<=(c=read())&&c<='9');return neg?-v:v;}public long nextLong(){consume();long v=0;char c=read();boolean neg=c=='-';if(neg)c=read();do{v=v * 10+c - '0';}while('0'<=(c=read())&&c<='9');return neg?-v:v;}private char read(){if(ptr==len)fill();return ptr 0) { 42 | RottenTomato tomato = queue.poll(); 43 | for (int[] d : deltas) { 44 | int nw = tomato.w + d[0]; 45 | int nv = tomato.v + d[1]; 46 | int nu = tomato.u + d[2]; 47 | int nt = tomato.t + d[3]; 48 | int ns = tomato.s + d[4]; 49 | int nr = tomato.r + d[5]; 50 | int nq = tomato.q + d[6]; 51 | int np = tomato.p + d[7]; 52 | int no = tomato.o + d[8]; 53 | int nn = tomato.n + d[9]; 54 | int nm = tomato.m + d[10]; 55 | 56 | if (isIn(nw, nv, nu, nt, ns, nr, nq, np, no, nn, nm)) { 57 | queue.add(new RottenTomato(nw, nv, nu, nt, ns, nr, nq, np, no, nn, nm)); 58 | map[nw][nv][nu][nt][ns][nr][nq][np][no][nn][nm] = BLOCK; 59 | if (--nOfTomatos == 0) { // 만약 모든 토마토가 사라졌다면 종료합니다. 특히 반복이 많기 때문에, 해당 부분에서 종료해서 최적화를 해주어야 합니다. 60 | break loop; 61 | } 62 | } 63 | } 64 | } 65 | } 66 | return days; 67 | } 68 | ``` 69 | 70 | 71 | ## 전체 코드 72 | ```java 73 | import java.io.*; 74 | import java.util.*; 75 | 76 | public class Main { 77 | static PScanner sc = new PScanner(System.in); 78 | static StringBuilder sb = new StringBuilder(); 79 | 80 | static StringTokenizer st; 81 | static int[][][][][][][][][][][] map; // 전체 맵입니다. 82 | static int nOfTomatos = 0; // 정상적인 토마토의 수입니다. 83 | 84 | static Queue queue; // bfs를 위한 queue입니다. 85 | static final int BLOCK = -1; 86 | 87 | static int m; 88 | static int n; 89 | static int o; 90 | static int p; 91 | static int q; 92 | static int r; 93 | static int s; 94 | static int t; 95 | static int u; 96 | static int v; 97 | static int w; 98 | 99 | // 22방향 이동 탐색 100 | static int[][] deltas = { 101 | {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 102 | {-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 103 | {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 104 | {0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 105 | {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, 106 | {0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0}, 107 | {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, 108 | {0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0}, 109 | {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, 110 | {0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0}, 111 | {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, 112 | {0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0}, 113 | {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, 114 | {0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0}, 115 | {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, 116 | {0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0}, 117 | {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, 118 | {0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0}, 119 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, 120 | {0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0}, 121 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 122 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, 123 | }; 124 | 125 | public static void main(String[] args) throws Exception { 126 | 127 | m = sc.nextInt(); 128 | n = sc.nextInt(); 129 | o = sc.nextInt(); 130 | p = sc.nextInt(); 131 | q = sc.nextInt(); 132 | r = sc.nextInt(); 133 | s = sc.nextInt(); 134 | t = sc.nextInt(); 135 | u = sc.nextInt(); 136 | v = sc.nextInt(); 137 | w = sc.nextInt(); 138 | map = new int[w][v][u][t][s][r][q][p][o][n][m]; // 맵의 크기를 받습니다. 해당 부분에서 유의해서 넣어줘야합니다. 139 | 140 | queue = new ArrayDeque<>(); 141 | // 입력을 받습니다. 142 | for (int ww = 0; ww < w; ww++) { 143 | for (int vv = 0; vv < v; vv++) { 144 | for (int uu = 0; uu < u; uu++) { 145 | for (int tt = 0; tt < t; tt++) { 146 | for (int ss = 0; ss < s; ss++) { 147 | for (int rr = 0; rr < r; rr++) { 148 | for (int qq = 0; qq < q; qq++) { 149 | for (int pp = 0; pp < p; pp++) { 150 | for (int oo = 0; oo < o; oo++) { 151 | for (int nn = 0; nn < n; nn++) { 152 | for (int mm = 0; mm < m; mm++) { 153 | int number = sc.nextInt(); 154 | if (number == 1) { 155 | queue.add(new RottenTomato(ww, vv, uu, tt, ss, rr, qq, pp, oo, nn, mm)); 156 | number = -1; 157 | } else if (number == 0) { 158 | nOfTomatos++; 159 | } 160 | map[ww][vv][uu][tt][ss][rr][qq][pp][oo][nn][mm] = number; 161 | } 162 | } 163 | } 164 | } 165 | } 166 | } 167 | } 168 | } 169 | } 170 | } 171 | } 172 | 173 | // 만약 시작부터 정상 토마토가 없다면 0 을 출력합니다. 174 | if (nOfTomatos == 0) { 175 | System.out.println(0); 176 | return; 177 | } 178 | 179 | // bfs를 돌면서 토마토를 처리합니다. 180 | int days = bfs(); 181 | if (nOfTomatos == 0) { // 정상 토마토가 0개가 되었다면 처리하는데 필요한 days를 작성합니다. 182 | System.out.println(days); 183 | } else // 모두 처리하지 못했다면 -1을 출력합니다. 184 | System.out.println(-1); 185 | 186 | 187 | } 188 | 189 | private static int bfs() { 190 | int days = 0; 191 | loop : while (!queue.isEmpty()) { 192 | int size = queue.size(); 193 | days++; // 바깥 반복이 시작될 때, 기간을 추가해줍니다. 194 | // 같은 너비에 있는 애들을 지웁니다. 195 | while (size-- > 0) { 196 | RottenTomato tomato = queue.poll(); 197 | for (int[] d : deltas) { 198 | int nw = tomato.w + d[0]; 199 | int nv = tomato.v + d[1]; 200 | int nu = tomato.u + d[2]; 201 | int nt = tomato.t + d[3]; 202 | int ns = tomato.s + d[4]; 203 | int nr = tomato.r + d[5]; 204 | int nq = tomato.q + d[6]; 205 | int np = tomato.p + d[7]; 206 | int no = tomato.o + d[8]; 207 | int nn = tomato.n + d[9]; 208 | int nm = tomato.m + d[10]; 209 | 210 | if (isIn(nw, nv, nu, nt, ns, nr, nq, np, no, nn, nm)) { 211 | queue.add(new RottenTomato(nw, nv, nu, nt, ns, nr, nq, np, no, nn, nm)); 212 | map[nw][nv][nu][nt][ns][nr][nq][np][no][nn][nm] = BLOCK; 213 | if (--nOfTomatos == 0) { // 만약 모든 토마토가 사라졌다면 종료합니다. 특히 반복이 많기 때문에, 해당 부분에서 종료해서 최적화를 해주어야 합니다. 214 | break loop; 215 | } 216 | } 217 | } 218 | } 219 | } 220 | return days; 221 | } 222 | 223 | // 해당 방향으로 이동 가능한지 체크하는 코드 224 | private static boolean isIn(int ww, int vv, int uu, int tt, int ss, int rr, int qq, int pp, int oo, int nn, int mm) { 225 | return ww >= 0 && ww < w && 226 | vv >= 0 && vv < v && 227 | uu >= 0 && uu < u && 228 | tt >= 0 && tt < t && 229 | ss >= 0 && ss < s && 230 | rr >= 0 && rr < r && 231 | qq >= 0 && qq < q && 232 | pp >= 0 && pp < p && 233 | oo >= 0 && oo < o && 234 | nn >= 0 && nn < n && 235 | mm >= 0 && mm < m && map[ww][vv][uu][tt][ss][rr][qq][pp][oo][nn][mm] == 0; 236 | } 237 | // Queue에서 사용할 토마토의 좌표 정보 238 | private static class RottenTomato { 239 | int w; 240 | int v; 241 | int u; 242 | int t; 243 | int s; 244 | int r; 245 | int q; 246 | int p; 247 | int o; 248 | int n; 249 | int m; 250 | 251 | public RottenTomato(int w, int v, int u, int t, int s, int r, int q, int p, int o, int n, int m) { 252 | this.w = w; 253 | this.v = v; 254 | this.u = u; 255 | this.t = t; 256 | this.s = s; 257 | this.r = r; 258 | this.q = q; 259 | this.p = p; 260 | this.o = o; 261 | this.n = n; 262 | this.m = m; 263 | } 264 | 265 | } 266 | // 입력 최적화 클래스 267 | static class PScanner{private final InputStreamReader in;private final char[]buf;private int len,ptr;public PScanner(InputStream input){in=new InputStreamReader(input);buf=new char[8192];}public boolean hasNext(){consume();return ptr' ';}public String next(){consume();char[]cbuf=new char[16];char clen=0;while((cbuf[clen++]=read())>' '){if(clen==cbuf.length)cbuf=Arrays.copyOf(cbuf,clen << 2);}return new String(cbuf,0,clen - 1);}public int nextInt(){consume();int v=0;char c=read();boolean neg=c=='-';if(neg)c=read();do{v=v * 10+c - '0';}while('0'<=(c=read())&&c<='9');return neg?-v:v;}public long nextLong(){consume();long v=0;char c=read();boolean neg=c=='-';if(neg)c=read();do{v=v * 10+c - '0';}while('0'<=(c=read())&&c<='9');return neg?-v:v;}private char read(){if(ptr==len)fill();return ptr 275 | 메모리 : 221736 KB
276 | 시간 : 968 ms
277 | 언어 : JAVA
--------------------------------------------------------------------------------