题目传送门: POJ 3273 Monthly Expense
题目概述: 给出M个月的花费dataSet[i], 要求划分N段,要求每组花费值尽可能的小,最后输出当前情况下,花费值最大的一组的值。
解题思路:看到最大和最小两个词,就应该想到这种模板问题,但是这里有个坑,就是二分查找的必要条件之一就是有序,仔细查看题目给的数据确实是无序的,而且位置顺序都有对应关系,题目要求每个月的区间都是连续的,无法进行排序操作。
经过分析,我们可以得到两种极端情况:
- 当M == 1的时候,我们只能取得一个分段,所以每个分组 == 整个分组 ,可以理解为区间的最大值end_flag == 当前数据之和
- 当M == N的时候,我们把每个数据都分为一个区间,所以可以理解为区间的最小值就是 当前数组中的最大值 ,即start_flag == 数组中的最大值
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
int N,M;
int dataSet[100000];
bool pd_section (int middle_value){
int cnt, sum;
cnt = 1;
sum = 0;
for (int i=0; i<N; i++){
sum += dataSet[i];
if (sum > middle_value ){
cnt++;
sum = dataSet[i];
}
if (cnt > M){
return false;
}
}
return true;
}
int main ()
{
while (cin>>N>>M)
{
int max_value = 0;
int sum_value = 0;
for (int i=0;i<N;i++){
cin>>dataSet[i];
sum_value += dataSet[i];
max_value = max(max_value, dataSet[i]);
}
int start_flag, end_flag;
start_flag = max_value;
end_flag = sum_value;
int middle_value;
while (start_flag <= end_flag){
middle_value = (start_flag + end_flag) / 2;
if ( pd_section(middle_value) ){
end_flag = middle_value - 1;
} else {
start_flag = middle_value + 1;
}
}
cout<<middle_value<<endl;
}
return 0;
}