POJ 3273 Monthly Expense(二分查找)

Monthly Expense
 

大意:给你天数N(1 ≤ N ≤ 100,000),和每天需要花的钱(存放在数组中),让你把这些天分成M(1 ≤ M ≤ N)份(每份都是连续的天),要求每份的和最大值尽量小,输出这个和。

思路:二分查找。让数组中的最大值为左界,数组的和为右界。左界的含义是将整个数组分成N块,那么和的最大值就是数组元素中的最大值。右界的含义是将整个数组当做一块,那么最大值就是所有数字之和。那么在左右界中(含左右界)的数肯定有一个是解。

二分搜索:给定一个初始数mid,从数组首元素开始叠加,超出mid那么分组数i加1,那么这么遍历一遍后能得到以mid为解所需的分组数,要是i小于M,说明mid给的大了,反之mid给小了,改变mid之后继续二分。

PS:最开始连题都没看懂,看了别人的题解终于找到一个能看懂的,虽然是二分做的,但是还是不知道二分的本质在什么地方,还要好好研究一下。

 1 #include <map>
 2 #include <stack>
 3 #include <queue>
 4 #include <math.h>
 5 #include <stdio.h>
 6 #include <string.h>
 7 #include <iostream>
 8 #include <algorithm>
 9 #define LL long long
10 using namespace std;
11 #define N
12 
13 int n, m;
14 ///通过每次比较group与m的大小,对mid值进行优化
15 bool find_mid(int mid, int a[])
16 {
17     int sum = 0;
18     int group = 1;   ///分组从1遍历到n
19     
20     ///从第一天开始向下遍历每天的花费
21     for(int i = 1; i <= n; i++)  
22     {
23         if(sum + a[i] <= mid)
24         {
25             ///当前i天之和<=mid时,把他们归并到一组
26             sum += a[i];
27         }
28         else  ///若 前i-1天之和 加上第i天的花费 大于mid
29         {
30             sum = a[i];///则把前i-1天作为一组,第i天作为下一组的第一天
31             group++;///此时分组+1
32         }
33     }
34     if(group > m)
35         return true;       ///mid值偏小
36     return false;         ///mid值偏大
37 }
38 
39 void run()
40 {
41     int a[100010];
42     while(~scanf("%d%d", &n, &m))
43     {
44         int right = 0;     ///一组划分的时候  上界
45         int left = 0;      ///n组划分的时候  下界
46         for(int i = 1; i <= n; i++)
47         {
48             scanf("%d", &a[i]);
49             right += a[i];         ///求上界
50             if(a[i] > left)
51             {
52                 left = a[i];       ///求下界
53             }
54         }
55         ///最后的答案肯定就在[left, right]中间
56         int mid = (right+left)/2;
57         while(left < right)        ///二分查找
58         {
59             if(find_mid(mid, a))
60             {
61                 left = mid + 1;     ///mid值偏小,下界前移
62             }
63             else
64             {
65                 right = mid - 1;    ///mid值偏大,上界后移
66             }
67             mid = (left+right)/2;
68         }
69         printf("%d\n", mid);     ///二分搜索最后得到的mid值必然是使得分组符合要求的最优值
70     }
71 }
72 
73 int main(void)
74 {
75     run();
76 
77     return 0;
78 }
Monthly Expense

 

 

 

注:参考代码:http://blog.csdn.net/lyy289065406/article/details/6648554

posted @ 2013-11-09 17:18  GLSilence  阅读(247)  评论(0编辑  收藏  举报