https://www.acmicpc.net/problem/1912
1912번: 연속합
첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.
www.acmicpc.net
문제
n개의 정수로 이루어진 임의의 수열이 주어진다. 우리는 이 중 연속된 몇 개의 수를 선택해서 구할 수 있는 합 중 가장 큰 합을 구하려고 한다. 단, 수는 한 개 이상 선택해야 한다.
예를 들어서 10, -4, 3, 1, 5, 6, -35, 12, 21, -1 이라는 수열이 주어졌다고 하자. 여기서 정답은 12+21인 33이 정답이 된다.
입력
첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.
출력
첫째 줄에 답을 출력한다.
해설
다른 방법들도 있지만 나는 분할 정복을 이용해서 문제를 해결하였다.
분할 정복이란 더 작은 문제들로 분할하여 문제를 해결해나가는 것이다.
인덱스의 최소값을 start, 최대값을 end, 중간값을 mid라고 하자.
이 때 최대 합이 있을 수 있는 구간은
1. [start ~ mid]에 최대 합이 있는 경우
2. [mid+1 ~ end]의 최대 합이 있는 경우
3. 최대 합이 중간에 걸쳐있는 경우
따라서 배열을 분할하여 위의 세가지 경우에서 만들어지는 값 중 최대값을 선택해가면
원하는 값을 얻을 수 있다.
소스 코드
import java.util.*
fun main() = with(System.`in`.bufferedReader()) {
val n = readLine().toInt()
val arr = IntArray(n)
val st = StringTokenizer(readLine())
for(i in 0 until n) arr[i] = st.nextToken().toInt()
println(divideConquer(arr, 0, n-1))
}
fun divideConquer(arr: IntArray, start: Int, end: Int): Int {
if(start == end) return arr[start]
val mid = (start + end) / 2
var left = Int.MIN_VALUE
var right = Int.MIN_VALUE
var sum = 0
for(i in mid downTo start) {
sum += arr[i]
left = maxOf(left, sum)
}
sum = 0
for(i in mid + 1 .. end) {
sum += arr[i]
right = maxOf(right, sum)
}
val side = maxOf(divideConquer(arr, start, mid), divideConquer(arr, mid+1, end))
return maxOf(left + right, side)
}
'PS(Problem Solving) > BOJ' 카테고리의 다른 글
[백준/BOJ]1927번: 최소 힙 (0) | 2022.03.27 |
---|---|
[백준/BOJ] 6603번: 로또 (0) | 2022.03.27 |
[백준/BOJ] 1788번: 피보나치 수의 확장 (0) | 2022.03.26 |
[백준/BOJ] 12847번: 꿀 아르바이트 (0) | 2022.03.06 |
[백준/BOJ] 3758번: KCPC (0) | 2022.03.06 |
댓글