和菜鸟一起学算法之二分法求极值问题

时间:2022-06-02 00:22:27

         ACM,大学最开始接触的,也是让我学到最多的东西,至此还没有忘记。记得当初寒假一个人默默地学习C语言,从变量,从函数。回到学校后,看着同学都在游戏之中,而自己每天默默地切题,有时还比他们还要晚。可是付出了,不一定有回报,比赛是一个团队,不是单靠个人,虽然我们的个人能力是没有问题的,但是,ACM还要靠RP。哈哈。。。总结下,主要还是自己的基础不够扎实,不够深入理解,只是知道这道题目怎么AC了,就草草地结束了,没有总结,没有透彻的吃进去。

         无聊之际,得把以前学的都总结下,为了留下足迹,为了养成学到什么总结什么的好习惯。不是有说男人20几岁就要开始养成写作的习惯嘛。以前学的算法都基本上忘得差不多了,以前放在网易Blog中的一些文章,在此拿出来继续看看,可能会觉得不一样的意境。也可以再次充实下自己。

        关于求极值,很多时候利用数学知识还是可以很好解决的,不过人是懒的,可以不用大脑,就不用了,什么事情都可以让计算机去实现。如果要用数学方法的话,求导还是可以求出最大值,最小值的,不过定义域范围什么的,有时会比较恶心。还是用我们的计算机来实现吧。让计算机来计算极值。

        二分法,其中二分好像比较熟悉吧,对的,二分查找?查找用二分的话,那么时间复杂度可以降低到O(log2n)。不断地去逼近我们要找的那个值。比如已经排序好的

        a[9] = {123456789}

        如果我们要查找6,一般情况下,我们是从123。。。这样慢慢找下去的。不过用二分的话,

               l=0r=8m=(l+r)/2=4,a[m] = 5

        发现56小,所以应该在m-r这个范围内,接着

              l=4,   r=8,      m=(l+r)/2=6a[m]=7,

        比较发现76大,所以这个值应该在l-m之间,即a[4]-a[6]之间,然后再次下去,就找到了6。就这么简单。而二分求极值,其实和这个差不多,只是他加进了函数,判断的条件不比较mid这个值和所要找的值。具体来看看下面这道题目吧。

 

xmu 1214.购物

Time Limit: 1000 MS         Memory Limit: 65536 K

Total Submissions: 263 (60 users)         Accepted: 68 (49 users)

[ My Solution ]

 

Description

为了组织班级聚会,wlnwyyfc来到新华都购买一种物品,这类物品的价值为P。他身上有N笔款项,每笔款项都有相应的价值。他希望使用这些款项至少要买M件这类物品,但是款项必须要单独使用,即不能合在一起去购买。问物品的价值P(必须为正整数)最大能为多少?

 

Input

第一行输入两个整数N(1<=N<=100,000)M(1<=M<=1,000,000,000)

接下来输入N个正整数ai(1<=ai<=1,000,000,000),表示N笔款项的价值。

 

Output

输出一个数,表示P的最大值。如果没有满足的值,输出-1

 

Sample Input

3 4

10 5 2

 

Sample Output

3

 

Source

wlnwyyfc@xmu

 

这个题目就是对价值p进行二分求最大值

#include <stdio.h>

int main()

{

 int n, m, a[100001], i, sum = 0;

 scanf("%d%d", &n, &m);

 for(i = 0; i < n; i++)

 {

  scanf("%d", &a[i]);

  if(sum < a[i]) sum = a[i];//先求出最大的款项

 }

 int l = 1, r = sum, mid; 最大的价值p肯定是1到这最大的款项之间。

 while(1)           //下面也可以算作是二分的框架吧

 {

  mid = (l + r) / 2;

  int cnt = 0;

  for(i = 0; i < n; i++)                        

   cnt += a[i] / mid;         //表示最多可以买的件数

  if(l >= r-1)            //这里表示已经二分完了

  {

   if(cnt >= m){printf("%d\n", mid); break;}        //表明有这个最大值

   else {printf("-1\n"); break;}

  }

  if(cnt >= m)l = mid;                这个和二分查找没什么区别吧?

  else if(cnt < m) r = mid;

 }

return 0;

}

 

        二分还是比较简单的,因为我们都学过二分查找,也就是折半查找,不过还有三分法,哈哈,这个三分法一开始我还没有十分明白。到点吃饭了,唉,通货膨胀,物价就这么涨了,吃个饭也这么贵。吃完再来分析分析三分法求极值问题吧。。。。