poj 3273 Monthly Expense 【二分搜索(最大化最小值)】

来源:互联网 发布:阿里云提供哪些服务 编辑:程序博客网 时间:2024/05/16 23:42
Monthly Expense

Time Limit: 2000MS

 

Memory Limit: 65536K

Total Submissions: 18798

 

Accepted: 7515

Description

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 nextN (1 ≤ N ≤ 100,000) days.

FJ wants to create a budget for a sequential set of exactly M (1 ≤ MN) 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.

Input

Line 1: Two space-separated integers: N andM
Lines 2..N+1: Line i+1 contains the number of dollars Farmer John spends on theith day

Output

Line 1: The smallest possible monthly limit Farmer John can afford to live with.

Sample Input

7 5100400300100500101400

Sample Output

500

Hint

If Farmer John schedules the months so that the first two days are a month, the third and fourth are a month, and the last three are their own months, he spends at most $500 in any month. Any other method of scheduling gives a larger minimum monthly limit.

Source

USACO 2007 March Silver
 
思路:
 
        给出你N个数,分别代表N天的花费,然后让你将任意个(也可以是一个)组合起来,组成M组在M组中求大值(这个最大值是比其他组合的最大值都要小)!
      
       因此,你需要将花费的可能的最大值和最小值都求出来,然后在这个范围内来查找你要找得的最大值(在这个过程中你是需要用到二分搜做的)!而查找最大值的过程中,是要满足一定的条件的,也就是说,你要的最大值是需要将相连的天数的花费(任意个,但是需要小于你查找的值)相加,然后总共的组数需要小于等于题目要求的值,最终通过二分查找,找到这个所求最大值的最小化!
 
AC代码
 
//s的大小最容易搞迷了,所以你要一边写代码,一遍写注释,来提示自己 #include <stdio.h>#include <string.h>#include <algorithm>using namespace std;int N,M;int a[1000005];int C(int s){int cnt=1;int sum=0;for(int i=0;i<N;i++){if(sum+a[i]<=s){sum+=a[i];}else{sum=a[i];cnt++;}}if(cnt<=M)//说明分的组数太少了,也就是s设的太大了! return 1;else//s设的太小了! return 0;}int main(){while(scanf("%d%d",&N,&M)!=EOF){int max=0,min=0;for(int i=0;i<N;i++){scanf("%d",&a[i]);if(min<a[i])min=a[i];//a中的最大值作为下线 max+=a[i];//所有元素的和作为上线 }int l=min-1,r=max+1;while(r-l>1)//不能写成while(r>l),会形成死循环 {int mid=(l+r)/2;if(C(mid))//条件成立,说明s太大了,所以你可以将s调小一点 r=mid;//也就是将另上线为中间值 else//否则说明s太小了,你需要找一个大一点的值 l=mid;//让下线为中间值! }printf("%d\n",r);}return 0;}

wa代码:(不知道为什么错了,请大神指点)
 
//错误代码!不知道为什么错了! #include <stdio.h>#include <string.h>#include <algorithm>using namespace std;int N,M;int a[1000005];int C(int s){int cnt=1;int sum=0;for(int i=0;i<N;i++){sum=a[i];int j;for(j=i+1;j<N;j++){if(sum+a[i]<=s){sum+=a[i];}else{break;}}i=j-1;cnt++;}if(cnt<=M)//说明分的组数太少了,也就是s设的太大了! return 1;else//s设的太小了! return 0;}int main(){while(scanf("%d%d",&N,&M)!=EOF){int max=0,min=0;for(int i=0;i<N;i++){scanf("%d",&a[i]);if(min<a[i])min=a[i];//a中的最大值作为下线 max+=a[i];//所有元素的和作为上线 }int l=min-1,r=max+1;while(r-l>1)//不能写成while(r>l),会形成死循环 {int mid=(l+r)/2;if(C(mid))//条件成立,说明s太大了,所以你可以将s调小一点 r=mid;//也就是将另上线为中间值 else//否则说明s太小了,你需要找一个大一点的值 l=mid;//让下线为中间值! }printf("%d\n",r);}return 0;}

 
0 0
原创粉丝点击