Skip to content

[Bona1122] 25.02.27#52

Merged
JooKangsan merged 10 commits intocodingTestStd:mainfrom
bona1122:bona1122
Mar 13, 2025
Merged

[Bona1122] 25.02.27#52
JooKangsan merged 10 commits intocodingTestStd:mainfrom
bona1122:bona1122

Conversation

@bona1122
Copy link
Collaborator

📌 푼 문제

📝 간단한 풀이 과정

N과 M(1)

// 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)

N과 M(2)

// 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)

N과 M(3)

// 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"))

N과 M(4)

// 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"))

부분수열의 합

// 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)

로또

// 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())

연산자 끼워넣기

// 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)

N-Queen

// 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
}

소수 찾기

// 소수인지판별하는 함수
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
}

양궁대회

// 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
}

@bona1122 bona1122 self-assigned this Mar 11, 2025
@JooKangsan JooKangsan merged commit 1cbc9eb into codingTestStd:main Mar 13, 2025
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants