Link
https://www.acmicpc.net/problem/2613
Detail
당시 이분탐색 태그를 검색하고 들어온 문제라서 풀이법을 알 수 있었다. 태그를 모르고 풀었다면 아마 매우 고전했을 문제가 아니었을까.
각 그룹은 무조건 M개가 되어야 하는데, 이때 각 그룹의 숫자의 합의 최댓값이 최소가 되도록 분할하는 것이 목표다.
따라서, “각 그룹의 구슬 합이 a이하가 되도록 할 수 있는가?” 를 판단 함수로 잡고 매개변수 이분탐색을 돌리는 것이 해법이다. 단 이때 각 그룹은 최소한 하나의 구슬을 가져야 하므로, (판단 함수의 결과에는 영향이 없지만, 출력에서 각 그룹의 구슬 갯수를 반환해야 한다.) 이를 재배열 하는 과정까지만 걸쳐주면 문제를 해결할 수 있다.
Code
#include<bits/stdc++.h>
using namespace std;
#define DEBUG 1
int BeadCount;
int GroupCount;
vector<int> Beads;
// 각 그룹의 무게 합이 maxCapacity를 넘지 않도록 구슬을 그룹화하고, 그룹의 크기를 반환
bool TryGroupBeads(int maxCapacity, vector<int>& groupSizes) {
groupSizes.resize(GroupCount, 0);
vector<int> groupWeights(GroupCount, 0);
int curGroup = 0;
for(int i = 0; i < BeadCount; i++) {
while(true) {
bool thisGroupAvailable = groupWeights[curGroup] + Beads[i] <= maxCapacity;
if(thisGroupAvailable) {
groupWeights[curGroup] += Beads[i];
groupSizes[curGroup]++;
break;
} else {
curGroup++;
if(curGroup >= GroupCount) {
return false;
}
}
}
}
//재조정 : 모든 그룹이 최소 하나씩은 가져야 함
for(int i = GroupCount - 1; i > 0; i--) {
if(groupSizes[i] <= 0) {
int need = 1 - groupSizes[i];
groupSizes[i] += need;
groupSizes[i - 1] -= need;
} else break;
}
return true;
}
void solution() {
int left = 0;
int right = accumulate(Beads.begin(), Beads.end(), 0);
int result = right;
while(left <= right) {
int mid = (left + right) / 2;
vector<int> groupResult;
if(TryGroupBeads(mid, groupResult)) {
result = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
vector<int> groupResult;
TryGroupBeads(result, groupResult);
cout << result << endl;
for(int i = 0; i < GroupCount; i++) {
cout << groupResult[i] << " ";
}
}
int main() {
cin >> BeadCount;
cin >> GroupCount;
Beads.resize(BeadCount);
for (int i = 0; i < BeadCount; i++) {
cin >> Beads[i];
}
solution();
return 0;
}