diff --git a/bona1122/[week8]BackTracking/Archery_competition.js b/bona1122/[week8]BackTracking/Archery_competition.js new file mode 100644 index 0000000..f8bd20d --- /dev/null +++ b/bona1122/[week8]BackTracking/Archery_competition.js @@ -0,0 +1,64 @@ +// https://school.programmers.co.kr/learn/courses/30/lessons/92342 +// 핵심은 1. 각 점수에 대해 이길지 말지를 결정하는 것 +// 2. 이길 때, 최소한의 화살 사용하기 - 어피치보다 1개만 더 쏘면됨. => 최고점수 만들기 위해 화살 효율적 사용, 그리고 낮은점수를 많이 맞추는게 우선되므로 + +function solution(n, info) { + let maxDiff = 0 + let answer = [-1] + let lion = Array(11).fill(0) + + // level은 현재 검사 중인 점수(0부터 시작), count는 남은 화살 수 + function dfs(level, count) { + if (level == 10) { + lion[level] = count // 남은 화살은 모두 0점에 사용 + + let sum = 0 + for (let i = 0; i < 10; i++) { + if (lion[i] > info[i]) { + // 라이언이 점수 획득 + sum = sum + (10 - i) + } else if (lion[i] === info[i] && lion[i] === 0) { + // 둘다 점수획득 못함 + continue + } else if (lion[i] === info[i] || lion[i] < info[i]) { + // 어피치가 점수 획득 + if (info[i] > 0) sum = sum - (10 - i) + } + } + + if (sum > maxDiff) { + maxDiff = sum + answer = [...lion] + } else if (sum == maxDiff && sum > 0) { + // 점수차가 같으면 낮은 점수를 더 많이 맞힌 경우를 선택 + // 낮은 점수부터 비교 + for (let j = 10; j >= 0; j--) { + if (answer[j] == lion[j]) { + continue + } else if (lion[j] > answer[j]) { + answer = [...lion] + break + } else { + break + } + } + } + return + } + + // 1. 현재 점수는 포기하는 경우 (화살 0개 사용) + dfs(level + 1, count) + + // 2. 현재 점수에서 이기는 경우 (남은화살 있고, 어피치보다 1개 더 사용) + const neededArrows = info[level] + 1 + if (count >= neededArrows) { + lion[level] = neededArrows + dfs(level + 1, count - neededArrows) + lion[level] = 0 // 백트래킹 초기화 + } + } + + dfs(0, n) + + return maxDiff <= 0 ? [-1] : answer +} diff --git a/bona1122/[week8]BackTracking/Lotto/Lotto.js b/bona1122/[week8]BackTracking/Lotto/Lotto.js new file mode 100644 index 0000000..27b423c --- /dev/null +++ b/bona1122/[week8]BackTracking/Lotto/Lotto.js @@ -0,0 +1,31 @@ +// https://www.acmicpc.net/problem/6603 + +const filePath = + process.platform === "linux" + ? "/dev/stdin" + : require("path").join(__dirname, "input.txt") +const input = require("fs").readFileSync(filePath).toString().split("\n") +const log = console.log + +// k개의 수를 골라 집합 만들고 그 수만 가지고 번호 선택하기 +let answer = "" +for (let i = 0; i < input.length; i++) { + let [k, ...arr] = input[i].split(" ").map(Number) + if (k === 0) break + + const selected = Array(6) + const result = [] + const dfs = (depth, start) => { + if (depth === 6) { + result.push(selected.join(" ")) + return + } + for (let i = start; i < arr.length; i++) { + selected[depth] = arr[i] + dfs(depth + 1, i + 1) + } + } + dfs(0, 0) + answer += result.join("\n") + "\n\n" +} +log(answer.trim()) diff --git a/bona1122/[week8]BackTracking/Lotto/input.txt b/bona1122/[week8]BackTracking/Lotto/input.txt new file mode 100644 index 0000000..f0067af --- /dev/null +++ b/bona1122/[week8]BackTracking/Lotto/input.txt @@ -0,0 +1,3 @@ +7 1 2 3 4 5 6 7 +8 1 2 3 5 8 13 21 34 +0 \ No newline at end of file diff --git a/bona1122/[week8]BackTracking/NM1/NM1.js b/bona1122/[week8]BackTracking/NM1/NM1.js new file mode 100644 index 0000000..b54d30b --- /dev/null +++ b/bona1122/[week8]BackTracking/NM1/NM1.js @@ -0,0 +1,28 @@ +// https://www.acmicpc.net/problem/15649 + +const filePath = + process.platform === "linux" + ? "/dev/stdin" + : require("path").join(__dirname, "input.txt") +const input = require("fs").readFileSync(filePath).toString() +const log = console.log + +// "순서"가 있게, 1-N 중 "중복없이" M개를 선택하는 문제 +const [N, M] = input.split(" ").map(Number) +const selected = Array(M) // 총 M개를 고를 것임 +const visited = Array(N + 1).fill(false) // 중복선택 방지 위해 +const dfs = (depth) => { + if (depth === M) { + log(selected.join(" ")) + return + } + for (let i = 1; i <= N; i++) { + if (visited[i]) continue + selected[depth] = i + visited[i] = true + dfs(depth + 1) + visited[i] = false + } +} + +dfs(0, 1) diff --git a/bona1122/[week8]BackTracking/NM1/input.txt b/bona1122/[week8]BackTracking/NM1/input.txt new file mode 100644 index 0000000..af1e489 --- /dev/null +++ b/bona1122/[week8]BackTracking/NM1/input.txt @@ -0,0 +1 @@ +4 2 \ No newline at end of file diff --git a/bona1122/[week8]BackTracking/NM2/NM2.js b/bona1122/[week8]BackTracking/NM2/NM2.js new file mode 100644 index 0000000..c782463 --- /dev/null +++ b/bona1122/[week8]BackTracking/NM2/NM2.js @@ -0,0 +1,26 @@ +// https://www.acmicpc.net/problem/15650 + +const filePath = + process.platform === "linux" + ? "/dev/stdin" + : require("path").join(__dirname, "input.txt") +const input = require("fs").readFileSync(filePath).toString() +const log = console.log + +// 1-N 중 "중복없이" M개를 선택하는 문제, "오름차순" 정렬 필요 +// => 오름차순 조건으로 인해 for문에서 start 인덱스(현재 선택한 수보다 큰 수부터)를 사용하여 구현 +const [N, M] = input.split(" ").map(Number) + +const selected = Array(M) +const dfs = (depth, start) => { + if (depth === M) { + log(selected.join(" ")) + return + } + for (let i = start; i <= N; i++) { + selected[depth] = i + dfs(depth + 1, i + 1) + } +} + +dfs(0, 1) diff --git a/bona1122/[week8]BackTracking/NM2/input.txt b/bona1122/[week8]BackTracking/NM2/input.txt new file mode 100644 index 0000000..af1e489 --- /dev/null +++ b/bona1122/[week8]BackTracking/NM2/input.txt @@ -0,0 +1 @@ +4 2 \ No newline at end of file diff --git a/bona1122/[week8]BackTracking/NM3/NM3.js b/bona1122/[week8]BackTracking/NM3/NM3.js new file mode 100644 index 0000000..6f564b5 --- /dev/null +++ b/bona1122/[week8]BackTracking/NM3/NM3.js @@ -0,0 +1,28 @@ +// https://www.acmicpc.net/problem/15651 + +const filePath = + process.platform === "linux" + ? "/dev/stdin" + : require("path").join(__dirname, "input.txt") +const input = require("fs").readFileSync(filePath).toString() +const log = console.log + +// 1-N 중 "중복가능하게" "순서" 있이, M개를 선택하는 문제 +const [N, M] = input.split(" ").map(Number) +let result = [] + +const selected = Array(M) +const dfs = (depth) => { + if (depth === M) { + result.push(selected.join(" ")) + return + } + + for (let i = 1; i <= N; i++) { + selected[depth] = i + dfs(depth + 1) + } +} + +dfs(0) +log(result.join("\n")) diff --git a/bona1122/[week8]BackTracking/NM3/input.txt b/bona1122/[week8]BackTracking/NM3/input.txt new file mode 100644 index 0000000..af1e489 --- /dev/null +++ b/bona1122/[week8]BackTracking/NM3/input.txt @@ -0,0 +1 @@ +4 2 \ No newline at end of file diff --git a/bona1122/[week8]BackTracking/NM4/NM4.js b/bona1122/[week8]BackTracking/NM4/NM4.js new file mode 100644 index 0000000..9cb3cd1 --- /dev/null +++ b/bona1122/[week8]BackTracking/NM4/NM4.js @@ -0,0 +1,29 @@ +// https://www.acmicpc.net/problem/15652 + +const filePath = + process.platform === "linux" + ? "/dev/stdin" + : require("path").join(__dirname, "input.txt") +const input = require("fs").readFileSync(filePath).toString() +const log = console.log + +// 1-N 중 "중복가능하게" M개를 선택하는 문제, "오름차순" 정렬 필요 +// => 오름차순 조건으로 인해 for문에서 start 인덱스(현재 선택한 수 이상)를 사용하여 구현 + +const [N, M] = input.split(" ").map(Number) +const selected = Array(M) +let result = [] + +const dfs = (depth, start) => { + if (depth === M) { + result.push(selected.join(" ")) + return + } + for (let i = start; i <= N; i++) { + selected[depth] = i + dfs(depth + 1, i) + } +} + +dfs(0, 1) +log(result.join("\n")) diff --git a/bona1122/[week8]BackTracking/NM4/input.txt b/bona1122/[week8]BackTracking/NM4/input.txt new file mode 100644 index 0000000..af1e489 --- /dev/null +++ b/bona1122/[week8]BackTracking/NM4/input.txt @@ -0,0 +1 @@ +4 2 \ No newline at end of file diff --git a/bona1122/[week8]BackTracking/N_Queen.js b/bona1122/[week8]BackTracking/N_Queen.js new file mode 100644 index 0000000..67a082b --- /dev/null +++ b/bona1122/[week8]BackTracking/N_Queen.js @@ -0,0 +1,30 @@ +// https://school.programmers.co.kr/learn/courses/30/lessons/12952 + +function solution(n) { + let queens = [] + const possible = (row, col) => { + for (let [queenRow, queenCol] of queens) { + // 이미 놓인 퀸들과 비교하며, 배치가 가능한지. + if (queenRow === row || queenCol === col) return false // 같은 행/열 불가 + if (Math.abs(queenRow - row) === Math.abs(queenCol - col)) return false // 대각선 불가 + } + return true + } + + let cnt = 0 + const dfs = (row) => { + if (row === n) { + cnt++ + return + } + for (let col = 0; col < n; col++) { + if (possible(row, col)) { + queens.push([row, col]) + dfs(row + 1) + queens.pop() + } + } + } + dfs(0) + return cnt +} diff --git a/bona1122/[week8]BackTracking/Operator_insertion/Operator_insertion.js b/bona1122/[week8]BackTracking/Operator_insertion/Operator_insertion.js new file mode 100644 index 0000000..59c4635 --- /dev/null +++ b/bona1122/[week8]BackTracking/Operator_insertion/Operator_insertion.js @@ -0,0 +1,49 @@ +// https://www.acmicpc.net/problem/14888 + +const filePath = + process.platform === "linux" + ? "/dev/stdin" + : require("path").join(__dirname, "input.txt") +const input = require("fs").readFileSync(filePath).toString().trim().split("\n") +const log = console.log + +// N개로 이루어진 수열, N-1개의 연산자 +// +, -, x, /. (나눗셈은 몫만 취하기, 음수를 양수로 나눌떄는 양수로바꾸어 몫취하고 음수로 바꾸기) +// 최대, 최소 구하기 + +const N = +input[0] +const arr = input[1].split(" ").map(Number) +const ops = input[2].split(" ").map(Number) +let max = -Infinity +let min = Infinity + +const dfs = (depth, acc) => { + if (depth === N - 1) { + max = Math.max(max, acc) + min = Math.min(min, acc) + return + } + for (let i = 0; i < 4; i++) { + if (ops[i] > 0) { + ops[i] -= 1 + if (i === 0) { + dfs(depth + 1, acc + arr[depth + 1]) + } else if (i === 1) { + dfs(depth + 1, acc - arr[depth + 1]) + } else if (i === 2) { + dfs(depth + 1, acc * arr[depth + 1]) + } else { + if (acc < 0) { + dfs(depth + 1, -Math.floor(-acc / arr[depth + 1])) + } else { + dfs(depth + 1, Math.floor(acc / arr[depth + 1])) + } + } + ops[i] += 1 + } + } +} + +dfs(0, arr[0]) + +log(max + "\n" + min) diff --git a/bona1122/[week8]BackTracking/Operator_insertion/input.txt b/bona1122/[week8]BackTracking/Operator_insertion/input.txt new file mode 100644 index 0000000..f2aef3f --- /dev/null +++ b/bona1122/[week8]BackTracking/Operator_insertion/input.txt @@ -0,0 +1,3 @@ +6 +1 2 3 4 5 6 +2 1 1 1 \ No newline at end of file diff --git a/bona1122/[week8]BackTracking/Prime_finding.js b/bona1122/[week8]BackTracking/Prime_finding.js new file mode 100644 index 0000000..9e44740 --- /dev/null +++ b/bona1122/[week8]BackTracking/Prime_finding.js @@ -0,0 +1,36 @@ +// 소수인지판별하는 함수 +function isPrime(n) { + if (n < 2) return false + if (n === 2) return true // 2는 소수 + if (n % 2 === 0) return false // 짝수는 소수가 아님 + + for (let i = 3; i <= Math.sqrt(n); i += 2) { + if (n % i === 0) return false + } + return true +} + +// 조각 조합해서 소수 몇개 만들수 있는지 -> "중복없이" "순서있게" 고르기 +function solution(numbers) { + const set = new Set() + const visited = Array(numbers.length).fill(false) + const selected = [] + + const dfs = () => { + if (selected.length > 0) { + const num = Number(selected.join("")) + if (isPrime(num)) set.add(num) + } + + for (let i = 0; i < numbers.length; i++) { + if (visited[i]) continue + visited[i] = true + selected.push(+numbers[i]) + dfs() + visited[i] = false + selected.pop() + } + } + dfs() + return set.size +} diff --git a/bona1122/[week8]BackTracking/Subsequence_Sum/Subsequence_sum.js b/bona1122/[week8]BackTracking/Subsequence_Sum/Subsequence_sum.js new file mode 100644 index 0000000..09a6d13 --- /dev/null +++ b/bona1122/[week8]BackTracking/Subsequence_Sum/Subsequence_sum.js @@ -0,0 +1,47 @@ +// https://www.acmicpc.net/problem/1182 + +const filePath = + process.platform === "linux" + ? "/dev/stdin" + : require("path").join(__dirname, "input.txt") +const input = require("fs").readFileSync(filePath).toString().split("\n") +const log = console.log + +// 크기가 양수인 부분수열 중, 원소를 다 더한 값이 S가 되는 경우의 수 구하기 +const [N, S] = input[0].split(" ").map(Number) +const arr = input[1].split(" ").map(Number) +let count = 0 + +// 1. 비트마스킹을 활용한 부분집합 완전탐색 +// i = 1 부터해서, 크기가 0인 부분집합 제외 +for (let i = 1; i < 1 << N; i++) { + let sum = 0 + for (let j = 0; j < N; j++) { + // j번째 원소가 부분집합에 포함되어 있다면 + if (i & (1 << j)) sum += arr[j] + } + if (sum === S) count++ +} +// log(count) + +// 2. 백트래킹을 활용한 부분집합 완전탐색 +const selected = Array(N).fill(false) +let cnt = 0 +const dfs = (depth) => { + if (depth === N) { + let sum = 0 + for (let i = 0; i < selected.length; i++) { + if (selected[i]) sum += arr[i] + } + if (sum === S) cnt++ + return + } + dfs(depth + 1) // 선택안하고 넘어가기 + + // 선택하고 넘어가기 + selected[depth] = true + dfs(depth + 1) + selected[depth] = false +} +dfs(0) +log(S === 0 ? --cnt : cnt) diff --git a/bona1122/[week8]BackTracking/Subsequence_Sum/input.txt b/bona1122/[week8]BackTracking/Subsequence_Sum/input.txt new file mode 100644 index 0000000..1f5df2c --- /dev/null +++ b/bona1122/[week8]BackTracking/Subsequence_Sum/input.txt @@ -0,0 +1,2 @@ +5 0 +-7 -3 -2 5 8 \ No newline at end of file