zoukankan      html  css  js  c++  java
  • 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
    ", 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

  • 相关阅读:
    jQuery的平滑页面内锚定链接插件:$.smoothAnchor()
    分享10个超酷的jQuery动画教程
    jQuery技术在线小测试
    分享一个jQuery的小测验(Quiz)插件:jQuizzy
    (SqlServer)不公开存储过程sp_Msforeachtable与sp_Msforeachdb详解
    SQL Server实用操作小技巧集合
    如何加密和解密文件
    winform程序最小化到托盘后没法关机的解决方案
    SQL语句操作大全
    自定义事件
  • 原文地址:https://www.cnblogs.com/Silence-AC/p/3415847.html
Copyright © 2011-2022 走看看