Algorithm/BOJ

백준 2632 피자판매

삼쓰 웅쓰 2021. 4. 2. 13:14
728x90

출처: www.acmicpc.net/problem/2632

분류: 이분탐색


접근방식

이분탐색을 통해 해결해볼 수 있었습니다.

전체적인 풀이 과정은 다음과 같습니다.

1. 각 피자에서 가능한 피자 조각을 모두 구한다. (n == 1000 이므로 n^2 이면 충분합니다.)

2. 한쪽 피자에서 선택했을 경우 또는 하지 않을 경우 다른 쪽 피자의 값이 무엇이 되어야 할지 기대할 수 있기 때문에 이를 이분탐색으로 파악합니다.

 

가능한 피자 조각을 구할 때 주의해야 할 점은 피자 조각이 원형이라는 점입니다.

주어진 예제처럼 2 2 1 7 2 에서 피자 조각 경우를 구할 때, 원형으로 생각을 해줘야 합니다.

2 2 1 7 2  - 여기서 1부터 시작한다면 가능한 조합은 

[1], [1, 7], [1, 7, 2], [1, 7, 2, 2], [1, 7, 2, 2, 2] 

이 됩니다! 단 이때 마지막 5가지를 모두 선택하는 경우는 중복되니까 한 번만 포함시켜줘야 합니다.

저는 n-1 까지만 조합을 만들어주고 마지막에 한 번만 5가지를 모두 더한 조각을 추가해주는 방식으로 해결했습니다.

원형은 % 연산을 사용해서 해결해줄 수 있습니다.

for i in 0..<arr.count {
  var temp = 0
  for j in i..<i+arr.count-1 {
    temp += arr[j % arr.count]
    table[temp, default: 0] += 1
  }
}

그리고 저는 중복되는 건 딕셔너리로 개수만 체크해서 처리해줬습니다 :)

이때는 a와 b 에서 원하는 조각 조합을 찾았으면

a 에서 피자 조각 개수 * b에서 피자 조각 개수

로 처리를 해줘야겠죠?

 

해결방법

일단 a 조합에서 n까지를 돌면서 원하는 피자조각 - an 이 b에서 있나 쭉 확인을 했는데

b 에서만 원하는 피자 조각이 또 있는지 확인해줘야 해서 포문을 나오고 한 번 더 처리를 해줬습니다,.

더 효율적으로 처리할 수도 있을 거 같네요 @_@

 

let n = Int(readLine()!)!
let nm = readLine()!.split(separator: " ").map { Int(String($0))! }
var a = [Int]()
var b = [Int]()
for _ in 0..<nm[0] {
  a.append(Int(readLine()!)!)
}

for _ in 0..<nm[1] {
  b.append(Int(readLine()!)!)
}

func sum(_ arr: [Int]) -> [Int: Int] {
  var table = [Int: Int]()
  for i in 0..<arr.count {
    var temp = 0
    for j in i..<i+arr.count-1 {
      temp += arr[j % arr.count]
      table[temp, default: 0] += 1
    }
  }
  table[arr.reduce(0, +), default: 0] += 1
  return table
}

let aTable = sum(a)
let bTable = sum(b)

let sumA = [Int](aTable.keys).sorted()
let sumB = [Int](bTable.keys).sorted()

var resultCase = 0

for an in sumA where an <= n  {
  guard an != n else {
    resultCase += aTable[an]!
    break
  }
  
  if let bn = binarySearch(n-an) {
    resultCase += aTable[an]! * bTable[bn]!
  }
}

if let bn = binarySearch(n), let bCase = bTable[bn] {
  resultCase += bCase
}

func binarySearch(_ target: Int) -> Int? {
  var low = 0
  var high = sumB.count-1
  
  while low <= high {
    let mid = (low + high) / 2
    
    if sumB[mid] == target {
      return sumB[mid]
    } else if target < sumB[mid] {
      high = mid-1
    } else {
      low = mid+1
    }
  }
  
  return nil
}

print(resultCase)

 

배운점

피자조각 개수를 미리 구해놓는 데서 머리가 좀 안 굴러갔는데

찬찬히 적어가면서 이해를 했다.

메모메모..!