poj 3273 二分法变形——最大化最小值问题

题目传送门: POJ 3273 Monthly Expense

题目概述: 给出M个月的花费dataSet[i], 要求划分N段,要求每组花费值尽可能的小,最后输出当前情况下,花费值最大的一组的值。


解题思路:看到最大和最小两个词,就应该想到这种模板问题,但是这里有个坑,就是二分查找的必要条件之一就是有序,仔细查看题目给的数据确实是无序的,而且位置顺序都有对应关系,题目要求每个月的区间都是连续的,无法进行排序操作。

经过分析,我们可以得到两种极端情况:

  • 当M == 1的时候,我们只能取得一个分段,所以每个分组 == 整个分组 ,可以理解为区间的最大值end_flag == 当前数据之和
  • 当M == N的时候,我们把每个数据都分为一个区间,所以可以理解为区间的最小值就是 当前数组中的最大值 ,即start_flag == 数组中的最大值
所以题目的答案一定会在[start_flag = max_value , end_flag=sum_value]这个区间内部,这样的话,我们开始进行先关的查找,即满足M的情况下,进行区间的范围搜索,最后的middle_value一定是满足上述要求的唯一的结果


#include
#include
#include
#include
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; iif (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;icin>>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<return 0;
}

你可能感兴趣的:(ACM练习)