[TopCoder] CutSticks (막대들 자르기)
2023. 3. 5. 23:40ㆍAlgorithm
존은 다양한 길이의 막대기를 가지고 있다. 각 요소가 하나의 막대의 길이인 막대가 주어집니다.
그는 C번의 컷을 수행한다. 각각의 컷에서, 그는 그의 스틱 중 하나를 선택하고 그것을 임의의 양의 길이를 가진 정확히 두 개의 스틱으로 나눈다. 그 다음에 컷을 할 때 각각의 스틱을 다시 선택할 수 있습니다.
컷을 모두 소화한 뒤 길이순으로 스틱을 분류해 K번째(1-based) 스틱을 선택한다. 선택한 스틱의 최대 길이를 반환합니다. K개 이상의 스틱으로 끝나려면 최소한 필요한 만큼의 컷을 수행해야 합니다.
Definition
Class:
CutSticks
Method:
maxKth
Parameters:
vector <int>, int, int
Returns:
double
Method signature:
double maxKth(vector <int> sticks, int C, int K)
Examples
0)
{5, 8}
1
1
Returns: 8.0
John can make at most one cut. He should either cut the stick of length 5 (it doesn't matter where) or not make any cuts at all. If he makes no cuts, then after he sorts the sticks, they will be in the following order: {8, 5}. He chooses the 1st stick, which has length 8.
1)
{5, 8}
1
2
Returns: 5.0
Again, the easiest thing to do here is not make any cuts.
2)
{5, 8}
1
3
Returns: 4.0
John has 2 sticks and he can make at most one cut. In this case, since K is 3, he is required to make a cut so he can end up with 3 sticks. He should cut the longest stick into two equal sticks of length 4. After he sorts the sticks, they will be in the following order: {5, 4, 4}. He will choose the 3rd stick, which has length 4.
3)
{1000000000, 1000000000, 1}
2
5
Returns: 1.0
4)
{76, 594, 17, 6984, 26, 57, 9, 876, 5816, 73, 969, 527, 49}
789
456
Returns: 34.92
Notes
- Your return value must have an absolute or relative error less than 1e-9.
Your return value must have an absolute or relative error less than 1e-9.
→ 이분 탐색 문제이다.
각각 길이가 다른 막대들이 여러개가 있고, 임의의 막대를 선택하여 C번의 Cut을 수행한 후에
길이 내림차순으로 정렬한 후 K번째의 막대를 선택했을 때 가장 최대값이 나올 수 있도록 한다.
example 1을 살펴보자.
{5, 8}
C: 1
K : 2
막대 길이가 각각 5, 8이고 1번의 Cut 수행이 가능하다. 그러고 나서 2번째로 긴 막대의 길이를 반환한다.
먼저 1번의 Cut을 수행하지 않을 경우, 8, 5 순이므로 5가 반환된다.
그럼 Cut을 수행하게되면 8, 5 중 5을 Cut하게 되면 더 작은 값을 반환할 수 밖에 없다.
8을 두동강 내야하는데, 5보다 작은 수들(4, 4)로 하게되면 4를 반환하기 때문에 안되고,
해봐야 6, 2 (6, 5, 2)로 하든 5, 3 (5, 5, 3)으로 하든 결국에 5가 반환된다.
여기서 문제를 푸는 중요한 핵심 키를 얻을 수 있다.
가장 긴 K번째 막대의 길이를 반환하기 위해서는 특정 길이 X인 막대를 K개 만들어 주어야한다.
이 길이 X가 무엇인지에 대해서는 이분탐색으로 찾아야한다.
#include <vector>
#include <algorithm>
using namespace std;
class CutSticks{
public:
double maxKth(vector <int> sticks, int C, int K){
double low =0;
double high = 1e9;
double mid = 0;
이분 탐색을 위한 변수들을 선언한다.
for(int i=0; i<100; i++){
long long count = 0;
mid = (low + high)/2;
long long cut = 0;
for(int j=0; j<sticks.size(); j++){
long long pieceNum = (long)(sticks[j]/mid);
cut += max((long long)0, (pieceNum-1)); //1개도 못 만드는 경우 있으므로
count += pieceNum;
}
오차를 줄이기 위한 충분한 반복횟수로 100번을 돌리는 것으로 하고,
막대들 배열을 순회하면서 만들어지는 특정 길이 X의 토막 개수를 누적한다.
절단 내는 개수(만들어진 토막 개수-1), 토막 개수를 각각 누적해준다.
count -= max((long long)0, (cut-C));
일단 잘랐는데, 실제로 Cut할수 있는 횟수보다 큰 횟수를 잘랐을 경우 넘어선 만큼 토막 개수에서 빼준다.
if(count >= K){
low = mid;
}
else{
high = mid;
}
만들어진 전체 토막개수 count가 K보다 크다는 것은, 토막의 길이를 좀 더 키워도 된다는 소리이다.
return mid;
반복문 탈출 시 mid를 반환한다.
'Algorithm' 카테고리의 다른 글
[Algorithm] Subset(부분집합) 구하기 (0) | 2023.03.12 |
---|---|
[TopCoder] InfiniteSequence2(무한 수열) (0) | 2023.03.06 |
[TopCoder] NotTwo(2은 아냐) (0) | 2023.03.05 |
[TopCoder] CantorDust (칸토어 분진) (0) | 2023.03.05 |
[TopCoder] HamiltonPath (해밀턴 패스) (0) | 2023.03.01 |