문제

오늘은 스타트링크에 다니는 사람들이 모여서 축구를 해보려고 한다. 축구는 평일 오후에 하고 의무 참석도 아니다. 축구를 하기 위해 모인 사람은 총 N명이고 신기하게도 N은 짝수이다. 이제 N/2명으로 이루어진 스타트 팀과 링크 팀으로 사람들을 나눠야 한다.

BOJ를 운영하는 회사 답게 사람에게 번호를 1부터 N까지로 배정했고, 아래와 같은 능력치를 조사했다. 능력치 Sij는 i번 사람과 j번 사람이 같은 팀에 속했을 때, 팀에 더해지는 능력치이다. 팀의 능력치는 팀에 속한 모든 쌍의 능력치 Sij의 합이다. Sij는 Sji와 다를 수도 있으며, i번 사람과 j번 사람이 같은 팀에 속했을 때, 팀에 더해지는 능력치는 Sij와 Sji이다.

N=4이고, S가 아래와 같은 경우를 살펴보자.


i / j  1 2 3 4
1   1 2 3
2 4   5 6
3 7 1   2
4 3 4 5  

예를 들어, 1, 2번이 스타트 팀, 3, 4번이 링크 팀에 속한 경우에 두 팀의 능력치는 아래와 같다.

  • 스타트 팀: S12 + S21 = 1 + 4 = 5
  • 링크 팀: S34 + S43 = 2 + 5 = 7

1, 3번이 스타트 팀, 2, 4번이 링크 팀에 속하면, 두 팀의 능력치는 아래와 같다.

  • 스타트 팀: S13 + S31 = 2 + 7 = 9
  • 링크 팀: S24 + S42 = 6 + 4 = 10

축구를 재미있게 하기 위해서 스타트 팀의 능력치와 링크 팀의 능력치의 차이를 최소로 하려고 한다. 위의 예제와 같은 경우에는 1, 4번이 스타트 팀, 2, 3번 팀이 링크 팀에 속하면 스타트 팀의 능력치는 6, 링크 팀의 능력치는 6이 되어서 차이가 0이 되고 이 값이 최소이다.

입력

첫째 줄에 N(4 ≤ N ≤ 20, N은 짝수)이 주어진다. 둘째 줄부터 N개의 줄에 S가 주어진다. 각 줄은 N개의 수로 이루어져 있고, i번 줄의 j번째 수는 Sij 이다. Sii는 항상 0이고, 나머지 Sij는 1보다 크거나 같고, 100보다 작거나 같은 정수이다.

출력

첫째 줄에 스타트 팀과 링크 팀의 능력치의 차이의 최솟값을 출력한다.

내가 푼 풀이

- 이 문제는 무식하게 완전탐색방식으로 풀었다.

- N명의 인원이 주어지면 두팀으로 갈라지는데 팀당 N/2인원이 정해진다.

- 단 두팀이므로 한팀이 정해지면 자연스럽게 다른 한팀이 정해진다.

- 그래서 우리는 한팀만 정해지는 모든 경우의 수를 구하고 구한 팀과 다른 팀과의 능력치를 비교했다.

- 순열을 이용해 팀을 뽑아도 좋았지만 코드로 구현하기 어려워 dfs방식으로 팀을 꾸렸다.

 

import Foundation

// 입력받기
let N = Int(readLine()!)!
var S = [[Int]]()
var answer = Int.max

// 인덱스 접근 편의상 [0] 공백을 추가했다.
S.append([0])
for i in 0..<N {
    S.append([0] + readLine()!.split(separator: " ").map{Int(String($0))!})
}

// dfs
func dfs(index: Int, team: [Int]) {
    // 팀이 꾸려지면 능력치 계산
    if team.count == N / 2 {
        calculate(arr: team)
    } else {
        // 팀 꾸리기
        for i in 1..<N {
            if index + i <= N {
                dfs(index: index+i, team: team + [index+i])
            }
        }
    }
}
// 능력치 계산
func calculate(arr: [Int]) {
    var start = arr
    var link = [Int]()
    var startSum = 0
    var linkSum = 0
    // 구해진팀과 다른 팀
    for i in 1...N {
        if !start.contains(i) {
            link.append(i)
        }
    }
    // 능력치를 모두 더해준다.
    for i in 0..<N/2 {
        for j in 0..<N/2 {
            startSum += S[start[i]][start[j]]
            linkSum += S[link[i]][link[j]]
        }
    }

    answer = min(answer, abs(startSum - linkSum))
}

for i in 1...N {
    dfs(index: i, team: [i])
}

print(answer)

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-1182 부분수열의 합 Swift  (0) 2024.04.10
BOJ-15686 치킨 배달 Swift  (0) 2024.04.10
BOJ-14888 연산자끼워넣기 Swift  (0) 2024.04.08
BOJ-2309 일곱 난쟁이 Swift  (0) 2024.04.08
BOJ-9663 N-Queen Swift  (1) 2024.04.07

문제

N개의 수로 이루어진 수열 A1, A2, ..., AN이 주어진다. 또, 수와 수 사이에 끼워넣을 수 있는 N-1개의 연산자가 주어진다. 연산자는 덧셈(+), 뺄셈(-), 곱셈(×), 나눗셈(÷)으로만 이루어져 있다.

우리는 수와 수 사이에 연산자를 하나씩 넣어서, 수식을 하나 만들 수 있다. 이때, 주어진 수의 순서를 바꾸면 안 된다.

예를 들어, 6개의 수로 이루어진 수열이 1, 2, 3, 4, 5, 6이고, 주어진 연산자가 덧셈(+) 2개, 뺄셈(-) 1개, 곱셈(×) 1개, 나눗셈(÷) 1개인 경우에는 총 60가지의 식을 만들 수 있다. 예를 들어, 아래와 같은 식을 만들 수 있다.

  • 1+2+3-4×5÷6
  • 1÷2+3+4-5×6
  • 1+2÷3×4-5+6
  • 1÷2×3-4+5+6

식의 계산은 연산자 우선 순위를 무시하고 앞에서부터 진행해야 한다. 또, 나눗셈은 정수 나눗셈으로 몫만 취한다. 음수를 양수로 나눌 때는 C++14의 기준을 따른다. 즉, 양수로 바꾼 뒤 몫을 취하고, 그 몫을 음수로 바꾼 것과 같다. 이에 따라서, 위의 식 4개의 결과를 계산해보면 아래와 같다.

  • 1+2+3-4×5÷6 = 1
  • 1÷2+3+4-5×6 = 12
  • 1+2÷3×4-5+6 = 5
  • 1÷2×3-4+5+6 = 7

N개의 수와 N-1개의 연산자가 주어졌을 때, 만들 수 있는 식의 결과가 최대인 것과 최소인 것을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 수의 개수 N(2 ≤ N ≤ 11)가 주어진다. 둘째 줄에는 A1, A2, ..., AN이 주어진다. (1 ≤ Ai ≤ 100) 셋째 줄에는 합이 N-1인 4개의 정수가 주어지는데, 차례대로 덧셈(+)의 개수, 뺄셈(-)의 개수, 곱셈(×)의 개수, 나눗셈(÷)의 개수이다.

출력

첫째 줄에 만들 수 있는 식의 결과의 최댓값을, 둘째 줄에는 최솟값을 출력한다. 연산자를 어떻게 끼워넣어도 항상 -10억보다 크거나 같고, 10억보다 작거나 같은 결과가 나오는 입력만 주어진다. 또한, 앞에서부터 계산했을 때, 중간에 계산되는 식의 결과도 항상 -10억보다 크거나 같고, 10억보다 작거나 같다.

내가 푼 풀이

- 첫번째 방법으로 연산자는 왼쪽연산과 오른쪽연산으로 처음엔 그리디를 이용해 서로 최소가되면 최솟값, 서로 최대가되면 최댓값이 나올꺼라 예상했는데, 정답이 나오지않았다.

- 두번째 방법으로 아예 완전탐색을 해보는것인데, dfs를 이용해 연산자가 남아있을때까지 모든 경우의 수를 구해보는것 이었다.

 

import Foundation

// 입력받기
let N = Int(readLine()!)!
let A = readLine()!.split(separator: " ").map{Int(String($0))!}
var op = readLine()!.split(separator: " ").map{Int(String($0))!}
var maxNum = -1000000000
var minNum = 1000000000

// dfs
func dfs(num: Int, sum: Int) {
    if num == N-1 {
        maxNum = max(sum, maxNum)
        minNum = min(sum, minNum)
    } else {
        if op[0] > 0 {
            op[0] -= 1
            dfs(num: num+1, sum: sum + A[num+1])
            op[0] += 1
        }
        if op[1] > 0 {
            op[1] -= 1
            dfs(num: num+1, sum: sum - A[num+1])
            op[1] += 1
        }
        if op[2] > 0 {
            op[2] -= 1
            dfs(num: num+1, sum: sum * A[num+1])
            op[2] += 1
        }
        if op[3] > 0 {
            op[3] -= 1
            dfs(num: num+1, sum: sum / A[num+1])
            op[3] += 1
        }
    }
}

dfs(num: 0, sum: A[0])
print(maxNum)
print(minNum)

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-15686 치킨 배달 Swift  (0) 2024.04.10
BOJ-14889 스타트와 링크 Swift  (0) 2024.04.08
BOJ-2309 일곱 난쟁이 Swift  (0) 2024.04.08
BOJ-9663 N-Queen Swift  (1) 2024.04.07
BOJ-7568 덩치 Swift  (1) 2024.04.07

문제

왕비를 피해 일곱 난쟁이들과 함께 평화롭게 생활하고 있던 백설공주에게 위기가 찾아왔다. 일과를 마치고 돌아온 난쟁이가 일곱 명이 아닌 아홉 명이었던 것이다.

아홉 명의 난쟁이는 모두 자신이 "백설 공주와 일곱 난쟁이"의 주인공이라고 주장했다. 뛰어난 수학적 직관력을 가지고 있던 백설공주는, 다행스럽게도 일곱 난쟁이의 키의 합이 100이 됨을 기억해 냈다.

아홉 난쟁이의 키가 주어졌을 때, 백설공주를 도와 일곱 난쟁이를 찾는 프로그램을 작성하시오.

입력

아홉 개의 줄에 걸쳐 난쟁이들의 키가 주어진다. 주어지는 키는 100을 넘지 않는 자연수이며, 아홉 난쟁이의 키는 모두 다르며, 가능한 정답이 여러 가지인 경우에는 아무거나 출력한다.

출력

일곱 난쟁이의 키를 오름차순으로 출력한다. 일곱 난쟁이를 찾을 수 없는 경우는 없다.

내가 푼 풀이

- 일곱난쟁이의 키 합이 100으로 만들어야한다.

- 주어진 입력은 아홉난쟁이이므로, 아홉난쟁이의 합에서 두 난쟁이만 제거한 값이 100이된다면, 남은 일곱난쟁이가 정답이 된다.

import Foundation

// 입력받기
var lettles = [Int]()
for i in 0..<9 {
    lettles.append(Int(readLine()!)!)
}
lettles.sort(by: <)
// 아홉난쟁이키의 합과 난쟁이가 아닌 인덱스 저장용 튜플
var total = lettles.reduce(0, +)
var notLettlesIndex: (index1: Int, index2: Int) = (0,0)

// 완전탐색
for i in 0..<9 {
    var isFind = false
    for j in i+1..<9 {
        let sum = lettles[i] + lettles[j]
        if total - sum == 100 {
            isFind = true
            notLettlesIndex = (i,j)
        }
    }
    if isFind {
        break
    }
}

// 해당 난쟁이를 인덱스를 통해 제거하고, 위 2중 반복문 특성상 무조건 i < j 이므로 index1 < index2 이다.
// 반복문에 중간값이 제거가된다면 전체 인덱스가 -1로 변경되므로 참고해서 제거해준다.
lettles.remove(at: notLettlesIndex.index1)
lettles.remove(at: notLettlesIndex.index2-1)
for i in lettles {
    print(i)
}

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-14889 스타트와 링크 Swift  (0) 2024.04.08
BOJ-14888 연산자끼워넣기 Swift  (0) 2024.04.08
BOJ-9663 N-Queen Swift  (1) 2024.04.07
BOJ-7568 덩치 Swift  (1) 2024.04.07
BOJ-2805 나무 자르기 Swift  (1) 2024.04.07

문제

N-Queen 문제는 크기가 N × N인 체스판 위에 퀸 N개를 서로 공격할 수 없게 놓는 문제이다.

N이 주어졌을 때, 퀸을 놓는 방법의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N이 주어진다. (1 ≤ N < 15)

출력

첫째 줄에 퀸 N개를 서로 공격할 수 없게 놓는 경우의 수를 출력한다.

내가 푼 풀이

- 첫번째 고안한방법은 이차원 배열의 보드를 만들어 전부 순회하며 가능한 모든 경우의수를 구하려했다.

- 이는 O(n^n) 이나 걸리는 너무나 느린 알고리즘이였고, 역시나 시간초과가 떴다.

- 시간을 줄이는 방법을 모르겠어서, 다른 풀이를 참고해보니 이 문제는 백트래킹 문제였다.

- 또한 배열도 이차원 배열이 아닌 일차원 배열로도 풀 수 있다는걸 몰랐다.

 

-> 퀸의 공격범위 특성상 주어진 체스판에 같은 행에 퀸 두개 이상을 배치할 수 없다.

-> 우리는 배치된 퀸의 열과 대각선 방향만 확인하면 된다.

-> 여기서 일차원배열은 board[a] = b 라 하면 이는 a행 b열에 퀸을 배치한다. 라고 의미한다.

-> 같은 행에 두개이상 배치할 수 없기 때문에 1행부터 N행까지 순회하고, 각각 열마다 퀸을 배치해본다..

-> 퀸을 배치하고, 다음 행의 퀸을 배치할 수 있는 범위가 있는지 파악하고, 배치가 가능하다면 퀸을 배치하고 다음 행으로 이동한다.

-> 퀸을 배치할 범위가 존재하지 않다면 다시 돌아와 다른 배치가능한 곳에 배치한다.

-> 이렇게 퀸을 N개만큼 배치했다면 경우의 수 1을 올린다.

-> 여기서 배열 인덱스 특성상 두 원소 (x1, y1), (x2, y2)가 있을때, |x1- x2| == |y1-y2| 가 성립한다면 두 원소는 대각선 위치에 인접해있다고 한다.

0,0 0,1 0,2
1,0 1,1 1,2
2,0 2,1 2,2

배열에서 (1,1) 과 (0,2) 는 |1 - 0| == |1-2| 가 성립하므로 두 원소는 대각선 위치에 있다고 할 수 있다.

위 특성을 이용하여 퀸을 배치한다면 배치한 퀸의 대각선의 위치도 알 수 있게 된다.

 

import Foundation
// 입력받기
let N = Int(readLine()!)!
var arr = Array(repeating: -1, count: N)
var visited = Array(repeating: false, count: N)
var result = 0

// 범위 확인
func checkAttakable(index: Int) -> Bool {
    for i in 0..<index {
        // arr[index] == arr[i] : 같은 열에 존재하는가?
        // abs(arr[index] - arr[i]) == abs(index - i) : 대각선방향으로 존재하는가?
        if arr[index] == arr[i] || abs(arr[index] - arr[i]) == abs(index - i) {
            return false
        }
    }
    return true
}

// DFS
func dfs(index: Int) {
    // 모든 행에 배치됬다면 탈출
    if index == N {
        result += 1
        return
    }
    // 주어진 행의 열에 모두 배치해본다.
    for i in 0..<N {
        // 이미 배치된 퀸의 공격범위라면 패스
        if visited[i] { continue }
        arr[index] = i
        // 배치 가능한 곳인지 확인한다.
        if checkAttakable(index: index) {
            visited[i] = true
            // 배치 후 그다음 행에 배치하귀위해 dfs 재귀호출
            dfs(index: index+1)
            // 그 전에 탐색했던 범위를 모두 배치가능으로 돌려놓는다.(백트래킹을 위해)
            visited[i] = false
        }
    }
}

dfs(index: 0)
print(result)

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-14888 연산자끼워넣기 Swift  (0) 2024.04.08
BOJ-2309 일곱 난쟁이 Swift  (0) 2024.04.08
BOJ-7568 덩치 Swift  (1) 2024.04.07
BOJ-2805 나무 자르기 Swift  (1) 2024.04.07
BOJ-1072 게임 Swift  (1) 2024.04.06

문제

우리는 사람의 덩치를 키와 몸무게, 이 두 개의 값으로 표현하여 그 등수를 매겨보려고 한다. 어떤 사람의 몸무게가 x kg이고 키가 y cm라면 이 사람의 덩치는 (x, y)로 표시된다. 두 사람 A 와 B의 덩치가 각각 (x, y), (p, q)라고 할 때 x > p 그리고 y > q 이라면 우리는 A의 덩치가 B의 덩치보다 "더 크다"고 말한다. 예를 들어 어떤 A, B 두 사람의 덩치가 각각 (56, 177), (45, 165) 라고 한다면 A의 덩치가 B보다 큰 셈이 된다. 그런데 서로 다른 덩치끼리 크기를 정할 수 없는 경우도 있다. 예를 들어 두 사람 C와 D의 덩치가 각각 (45, 181), (55, 173)이라면 몸무게는 D가 C보다 더 무겁고, 키는 C가 더 크므로, "덩치"로만 볼 때 C와 D는 누구도 상대방보다 더 크다고 말할 수 없다.

N명의 집단에서 각 사람의 덩치 등수는 자신보다 더 "큰 덩치"의 사람의 수로 정해진다. 만일 자신보다 더 큰 덩치의 사람이 k명이라면 그 사람의 덩치 등수는 k+1이 된다. 이렇게 등수를 결정하면 같은 덩치 등수를 가진 사람은 여러 명도 가능하다. 아래는 5명으로 이루어진 집단에서 각 사람의 덩치와 그 등수가 표시된 표이다.

이름 (몸무게, 키) 덩치 등수
A (55, 185) 2
B (58, 183) 2
C (88, 186) 1
D (60, 175) 2
E (46, 155) 5

위 표에서 C보다 더 큰 덩치의 사람이 없으므로 C는 1등이 된다. 그리고 A, B, D 각각의 덩치보다 큰 사람은 C뿐이므로 이들은 모두 2등이 된다. 그리고 E보다 큰 덩치는 A, B, C, D 이렇게 4명이므로 E의 덩치는 5등이 된다. 위 경우에 3등과 4등은 존재하지 않는다. 여러분은 학생 N명의 몸무게와 키가 담긴 입력을 읽어서 각 사람의 덩치 등수를 계산하여 출력해야 한다.

입력

첫 줄에는 전체 사람의 수 N이 주어진다. 그리고 이어지는 N개의 줄에는 각 사람의 몸무게와 키를 나타내는 양의 정수 x와 y가 하나의 공백을 두고 각각 나타난다.

출력

여러분은 입력에 나열된 사람의 덩치 등수를 구해서 그 순서대로 첫 줄에 출력해야 한다. 단, 각 덩치 등수는 공백문자로 분리되어야 한다.

내가 푼 풀이

- 주어진 값들을 입력받아 완전탐색을 한다.

- 각각 사람과 다른사람들의 몸무게 키를 비교하여 덩치가 큰사람이 있다면 +1 하는 방법으로 2중 for문을 돈다.

 

import Foundation

// 입력받기
let N = Int(readLine()!)!
var person = [(index: Int, x: Int, y: Int)]()
var result = ""
for i in 0..<N{
    let input = readLine()!.split(separator: " ").map{Int(String($0))!}
    person.append((1,input[0], input[1]))
}

// 완전탐색
// 해당 인원과 다른 모든인원과 비교하여 덩치가 크면 +1
for i in 0..<N {
    for j in 0..<N {
        if person[i].x < person[j].x && person[i].y < person[j].y {
            person[i].index += 1
        }
    }
    if i == N - 1 {
        result += "\(person[i].index)"
    } else {
        result += "\(person[i].index) "
    }
}
print(result)

 

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-2309 일곱 난쟁이 Swift  (0) 2024.04.08
BOJ-9663 N-Queen Swift  (1) 2024.04.07
BOJ-2805 나무 자르기 Swift  (1) 2024.04.07
BOJ-1072 게임 Swift  (1) 2024.04.06
BOJ-2512 예산 Swift  (0) 2024.04.06

문제

상근이는 나무 M미터가 필요하다. 근처에 나무를 구입할 곳이 모두 망해버렸기 때문에, 정부에 벌목 허가를 요청했다. 정부는 상근이네 집 근처의 나무 한 줄에 대한 벌목 허가를 내주었고, 상근이는 새로 구입한 목재절단기를 이용해서 나무를 구할것이다.

목재절단기는 다음과 같이 동작한다. 먼저, 상근이는 절단기에 높이 H를 지정해야 한다. 높이를 지정하면 톱날이 땅으로부터 H미터 위로 올라간다. 그 다음, 한 줄에 연속해있는 나무를 모두 절단해버린다. 따라서, 높이가 H보다 큰 나무는 H 위의 부분이 잘릴 것이고, 낮은 나무는 잘리지 않을 것이다. 예를 들어, 한 줄에 연속해있는 나무의 높이가 20, 15, 10, 17이라고 하자. 상근이가 높이를 15로 지정했다면, 나무를 자른 뒤의 높이는 15, 15, 10, 15가 될 것이고, 상근이는 길이가 5인 나무와 2인 나무를 들고 집에 갈 것이다. (총 7미터를 집에 들고 간다) 절단기에 설정할 수 있는 높이는 양의 정수 또는 0이다.

상근이는 환경에 매우 관심이 많기 때문에, 나무를 필요한 만큼만 집으로 가져가려고 한다. 이때, 적어도 M미터의 나무를 집에 가져가기 위해서 절단기에 설정할 수 있는 높이의 최댓값을 구하는 프로그램을 작성하시오.

 

입력

첫째 줄에 나무의 수 N과 상근이가 집으로 가져가려고 하는 나무의 길이 M이 주어진다. (1 ≤ N ≤ 1,000,000, 1 ≤ M ≤ 2,000,000,000)

둘째 줄에는 나무의 높이가 주어진다. 나무의 높이의 합은 항상 M보다 크거나 같기 때문에, 상근이는 집에 필요한 나무를 항상 가져갈 수 있다. 높이는 1,000,000,000보다 작거나 같은 양의 정수 또는 0이다.

출력

적어도 M미터의 나무를 집에 가져가기 위해서 절단기에 설정할 수 있는 높이의 최댓값을 출력한다.

내가 푼 풀이

- 이분탐색으로 문제를 해결했다.

- 설정할 높이를 최소 0부터 최대 주어진 나무의 최대길이 까지 이분탐색후, 나무 배열을 순회하여 해당 높이만큼 자른다

- 자른 값이 상근이가 구하려는 높이보다 큰경우 높이를 더 높게설정(높을수록 나무는 짧게 베인다.)

- 자른 값이 상근이가 구하려는 높이보다 작은경우 높이를 더 낮게설정(낮을수록 나무는 길게 베인다.)

 

import Foundation

// 입력받기
let input = readLine()!.split(separator: " ").map{Int(String($0))!}
let trees = readLine()!.split(separator: " ").map{Int(String($0))!}
let N = input[0], M = input[1]
var result = 0

// 이분탐색의 left,rigt 인덱스
var start = 0
var end = trees.max()!

// 이분탐색
// 자른값이 구하려는 값보다 작다면 높이를 낮게설정(더많이 잘린다.)
// 자른값이 구하려는 값보다 크다면 높이를 높게설정(더적게 잘린다.)
while start <= end {
    let mid = (start + end) / 2
    var count = 0
    
    for i in 0..<trees.count {
        if mid < trees[i] {
            count += trees[i] - mid
        }
    }
    if count >= M {
        result = mid
        start = mid + 1
    } else {
        end = mid - 1
    }
}
print(result)

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-9663 N-Queen Swift  (1) 2024.04.07
BOJ-7568 덩치 Swift  (1) 2024.04.07
BOJ-1072 게임 Swift  (1) 2024.04.06
BOJ-2512 예산 Swift  (0) 2024.04.06
BOJ-2110 공유기 설치 Swift  (0) 2024.04.05

문제

김형택은 지금 몰래 Spider Solitaire(스파이더 카드놀이)를 하고 있다. 형택이는 이 게임을 이길 때도 있었지만, 질 때도 있었다. 누군가의 시선이 느껴진 형택이는 게임을 중단하고 코딩을 하기 시작했다. 의심을 피했다고 생각한 형택이는 다시 게임을 켰다. 그 때 형택이는 잠시 코딩을 하는 사이에 자신의 게임 실력이 눈에 띄게 향상된 것을 알았다.

이제 형택이는 앞으로의 모든 게임에서 지지 않는다. 하지만, 형택이는 게임 기록을 삭제 할 수 없기 때문에, 자신의 못하던 예전 기록이 현재 자신의 엄청난 실력을 증명하지 못한다고 생각했다.

게임 기록은 다음과 같이 생겼다.

  • 게임 횟수 : X
  • 이긴 게임 : Y (Z%)
  • Z는 형택이의 승률이고, 소수점은 버린다. 예를 들어, X=53, Y=47이라면, Z=88이다.

X와 Y가 주어졌을 때, 형택이가 게임을 최소 몇 번 더 해야 Z가 변하는지 구하는 프로그램을 작성하시오.

입력

각 줄에 정수 X와 Y가 주어진다.

출력

첫째 줄에 형택이가 게임을 최소 몇 판 더 해야하는지 출력한다. 만약 Z가 절대 변하지 않는다면 -1을 출력한다.

내가 푼 풀이

- 이문제를 어떻게 풀어야하는지 고민하는건 어렵지않았으나, 계산의 정확성에서 틀렸다.

- 앞으로 모든 게임을 이긴다고 했으니, 추가로 하는 판들은 모두 Y에 더해진다.

- 최소 한판부터 최대 게임횟수까지 이분탐색으로 Z값이 변하는 최솟값을 구하면된다.

- 여기서 승률을 구하는 문제에서 Double캐스팅후 계산을 했어도 정확성에 문제가 있었다.

- 100 * ( Y / X )로 구했다가 Int는 소숫점이 날아가고, Double은 큰값을 계산할때 정확성에 문제가 생겼다

- Y를 100 먼저 곱해준다음 X로 나눴더니 문제가 풀렸다 -> 100 * Y / X

- 이렇게 구한 새로운 승률이 기존승률과 같다면 승수를 더 늘린다. 승률이 올랐다면, 승수를 내려서 최솟값을 찾는다.

 

import Foundation

//입력받기
let input = readLine()!.split(separator: " ").map{Int(String($0))!}
let X = input[0], Y = input[1]
let Z = Y * 100 / X

// result = -1 (한판도 하지않는경우와 승률이 변하지않는경우)
// startIndex: 0, endIndex: X
var result = -1
var start = 0
var end = X

// 이분탐색
while start <= end {
    let mid = (start + end) / 2
    let newX = X + mid
    let newY = Y + mid
    let newZ = 100 * newY / newX
    // 승을 더해서 계산한 승률이 이전승률과 같다면, 승수를 늘려서 승률을 다르게 만든다.
    // 승을 더해서 계산한 승률이 이전승률과 다르다면, 승수를 줄여서 최솟값을 구한다
    if newZ == Z {
        start = mid + 1
    } else {
        result = mid
        end = mid - 1
    }
}
print(result)

 

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-7568 덩치 Swift  (1) 2024.04.07
BOJ-2805 나무 자르기 Swift  (1) 2024.04.07
BOJ-2512 예산 Swift  (0) 2024.04.06
BOJ-2110 공유기 설치 Swift  (0) 2024.04.05
BOJ-1654 랜선 자르기 Swift  (0) 2024.04.05

문제

국가의 역할 중 하나는 여러 지방의 예산요청을 심사하여 국가의 예산을 분배하는 것이다. 국가예산의 총액은 미리 정해져 있어서 모든 예산요청을 배정해 주기는 어려울 수도 있다. 그래서 정해진 총액 이하에서 가능한 한 최대의 총 예산을 다음과 같은 방법으로 배정한다.

  1. 모든 요청이 배정될 수 있는 경우에는 요청한 금액을 그대로 배정한다.
  2. 모든 요청이 배정될 수 없는 경우에는 특정한 정수 상한액을 계산하여 그 이상인 예산요청에는 모두 상한액을 배정한다. 상한액 이하의 예산요청에 대해서는 요청한 금액을 그대로 배정한다. 

예를 들어, 전체 국가예산이 485이고 4개 지방의 예산요청이 각각 120, 110, 140, 150이라고 하자. 이 경우, 상한액을 127로 잡으면, 위의 요청들에 대해서 각각 120, 110, 127, 127을 배정하고 그 합이 484로 가능한 최대가 된다. 

여러 지방의 예산요청과 국가예산의 총액이 주어졌을 때, 위의 조건을 모두 만족하도록 예산을 배정하는 프로그램을 작성하시오.

입력

첫째 줄에는 지방의 수를 의미하는 정수 N이 주어진다. N은 3 이상 10,000 이하이다. 다음 줄에는 각 지방의 예산요청을 표현하는 N개의 정수가 빈칸을 사이에 두고 주어진다. 이 값들은 모두 1 이상 100,000 이하이다. 그 다음 줄에는 총 예산을 나타내는 정수 M이 주어진다. M은 N 이상 1,000,000,000 이하이다. 

출력

첫째 줄에는 배정된 예산들 중 최댓값인 정수를 출력한다. 

내가 푼 풀이

- 예산을 1부터 모두 넣어보고 모든 지방들이 예산을 받았다면 수를 계속 늘려 최대값을 구해본다.

- 위는 단순히 1부터 더한다면 아마 시간초과가 날것으로, 이분탐색을 이용해 값을 구해본다.

- 이분탐색의 startIndex는 상한액의 최솟값인 1이되고, endIndex는 최댓값인 주어진 지방중 가장 큰 금액이 된다.

- 지방들을 오름차순으로 정렬하고 이분탐색을 시작해서 값을 구해낸다

 

import Foundation

// 입력받기
let N = Int(readLine()!)!
let want = readLine()!.split(separator: " ").map{Int(String($0))!}
let money = Int(readLine()!)!
// start: 1, end는 지방중 예산이 가장필요로하는곳의 값
var sortedWants = want.sorted(by: <)
var start = 1
var end = sortedWants[sortedWants.endIndex - 1]
var result = 1

// 이분탐색
// 주어진 상한액(mid)로 모든 지방에 예산을 넣었다면, 상한액을 올려보고, 예산을 넣지 못했다면 상한액을 낮춰본다.
while start <= end {
    var count = 0
    var m = money
    var mid = (start + end) / 2
    for i in 0..<sortedWants.count {
        if m >= mid {
            if mid >= sortedWants[i] {
                m -= sortedWants[i]
                count += 1
            } else if mid < sortedWants[i] {
                m -= mid
                count += 1
            }
        }
    }
    if count == N {
        result = mid
        start = mid + 1
    } else {
        end = mid - 1
    }
    
}

print(result)

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-2805 나무 자르기 Swift  (1) 2024.04.07
BOJ-1072 게임 Swift  (1) 2024.04.06
BOJ-2110 공유기 설치 Swift  (0) 2024.04.05
BOJ-1654 랜선 자르기 Swift  (0) 2024.04.05
BOJ-1920 수 찾기 Swift  (0) 2024.04.05

+ Recent posts