【二分答案题目整理】—— 最大化最小值 + 最大值最小化(下)

上一篇博客主要讲了最大化最小值。 今天的下篇就主要说最大值最小化
因为同样属于二分答案地题型,所以思路当然还是二分答案的思路。
不妨复习一下:先找到答案的可能区间,然后判断答案是否满足题目所给的操作条件,根据操作条件的多少来进行二分区间的改变。几乎二分答案的题目都是此等套路。
下面给一个最大值最小化的题目 ;

POJ 3273 Monthly Expense

Farmer John is an astounding accounting wizard and has realized he might run out of money to run the farm. He has already calculated and recorded the exact amount of money (1 ≤ moneyi ≤ 10,000) that he will need to spend each day over the next N (1 ≤ N ≤ 100,000) days.
FJ wants to create a budget for a sequential set of exactly M (1 ≤ M ≤ N) fiscal periods called “fajomonths”. Each of these fajomonths contains a set of 1 or more consecutive days. Every day is contained in exactly one fajomonth.
FJ’s goal is to arrange the fajomonths so as to minimize the expenses of the fajomonth with the highest spending and thus determine his monthly spending limit.

Sample Input
7 5
100
400
300
100
500
101
400
Sample Output
500

简单来讲就是将N个东西分成M份,这M份每份和的总上界为最大花费,现在要求出这个最大花费的最小值。
思路:
要求的就是一个花费,那么因为这个花费是每组的最大花费,因而肯定大于整个数据中最大的一个(分成n组),同时小于所有数的和(分成一组)。二分区间就是[max,sum]。
现在我们要求的就是,当知道每组最大消费额为x时,能够分成多少组。从头到尾依次遍历,当大于额度x时就cnt++,因为数据分散,每一个cnt对应的是一个额度区间。额度越大,分的组越少,F(x)是一个单调减的函数。我们要求的就是
F(x) <= M时最小的x。

需要注意的是,当所划分的次数大于目标次数时,预算一定是太低。而当划分次数小于等于M时,一定会有此题的答案。即如:14是分8组的最低预算,但同样也是9组10组的最低预算,因为比14 低的13是分11组时的最低预算。也就是说,也许F(x) < M但x依然是M对应的最优解。并不是每一个M都有F(x)与之对应,我们要找的只是F(x)小于等于M的最大的x。

每次想把问题讲清楚都需要啰嗦好一大段
贴代码:

#include
#include
#include
using namespace std;
//最大值最小化的基本方法  //有空档期,即不是一一对应的约束条件 
int N,M;
const int max_n = 1000000;
int mon[max_n];
long long ans = 0;
long long sum = 0;
int maxx = 0;
long long int mid;
long long int can(long long lb,long long ub)
{
 long long temp = 0;
 int cnt = 1;
 if(lb<ub)
 {
 mid = (ub+lb)/2;
 for(int i=0;i<N;i++)
 {
  if(temp+mon[i]>mid)
  {
   cnt++;
   temp = mon[i];
  }
  else
  {
   temp += mon[i];
  }
 }
 if(cnt <= M)
 {
  can(lb,mid);//所找到的唯一解,只会在本质上更优。比如14是分8组时的最优解,那么在9组10组时也可能会同样成立。因为没有更低的选择,即会出现空档,即13可能是分11组时的最优解。 
 }               //这大概会是最大值最小化时的独特情况,所以当真实cnt小于等于目标cnt时,也有可能是最终答案!!因此,细节在于:在这里将mid保留,并且最终代回mid处,也就是ub处的值。但大于目标cnt一定不是最终答案。 
 else
 {
  can(mid+1,ub);
 }
 }
 else return ub;
}
int main()
{
 scanf("%d%d",&N,&M);
 for(int i=0;i<N;i++)
 {
  scanf("%d",&mon[i]);
  maxx = max(maxx,mon[i]);
  sum+=mon[i];
 }
 printf("%lld\n",can(maxx,sum));
 return 0;
}

最近的两篇博客就是最近研究的二分法的内容了。
代码片里的第二行备注比较清楚的讲明白了为什么在 <= M时保留了(lb,mid)另一个保留的是(mid+1,ub) 这样最上面的约束条件就是(lb < ub)
整理一下最近的约束条件以及二分区间的选择的几种方法。

上下界约束 lb < ub ; lb <= ub ; ub - lb > 1
左区间约束 (lb,mid); (lb,mid-1) ; (lb,mid)
右区间约束 (mid+1,ub) ; (mid+1 ,ub) ; (mid,ub)

以上就非常清晰啦啦啦啦!!整理之后我也收获良多嘻嘻嘻。
最近的两篇博客写的都是关于二分的内容,到这里也就差不多了,讲道理多做题真的是最有效的方法(我真的太懒了 )。

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