编程珠矶学习笔记(9)--查找最大和(分治算法O(logn))

18 篇文章 0 订阅

个人原创,转载请注明出处,谢谢!

一、 目的

input: n个元素的数组;

output: 在数组中查找相邻数的最大和;

constrain: 如最大和为负数,则最大和为0,即一个也不选。

二、算法原理

要解决x[n]的最大和问题,可递归解决两个规模近似为n/2的子问题,然后将他们的答案进行合并以得到整个问题的答案。即如下图将x[n]转化为两个子数组x[a]x[b]

1

考虑到ab的并集也可能产生最大和,所以最大和只能在abab中的并集产生,如下图:

 2

即在子数组x[a]x[m]x[b]中产生。

 

 

 

三、  代码

#include <stdio.h>

#include <stdlib.h>

#include <time.h>

 

#define MAXN 10000000

int n;

float x[MAXN];

 

 

void sprinkle()

{  

int i;

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

        x[i] = 1 - 2*( (float) rand()/RAND_MAX);

}

}

 

float maxfun(float a, float b)

{  

   return a > b ? a : b;

}

 

#define max(a, b) maxfun(a, b)

 

float get_max_sum (int l, int u)

{  

int i, m;

float lmax, rmax, sum;

 

 

    if (l > u) { 

       return 0;

}

 

if (l == u) {

       return max(0, x[l]);

}

  

m = (l + u) / 2;

   

   lmax = sum = 0;

   for (i = m; i >= l; i--) {

       sum += x[i];

       if (sum > lmax)

           lmax = sum;

    }

   

    rmax = sum = 0;

    for (i = m + 1; i <= u; i++) {

       sum += x[i];

       if (sum > rmax) {

           rmax = sum;

}

    }

    return max(lmax + rmax,

       max(recmax(l, m), recmax(m+1, u)));

}

 

int main()

{

    float max_sum;

 

    while (scanf("%d", &n) != EOF) {

       sprinkle();

       start = clock();

       max_sum = -1.0;

max_sum = get_max_sum();

printf(max sum = %f/n, max_sum);

}

 

    return 0;

}

 

四、代码注解

 

/*使用随机数[-11]填充数组,使得数组内元素有正有负,且随机排布*/

void sprinkle()

{  

int i;

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

        x[i] = 1 - 2*( (float) rand()/RAND_MAX);

}

}

 

float maxfun(float a, float b)

{   return a > b ? a : b;

}

 

#define max(a, b) maxfun(a, b)

 

/*求数组x[l,u]内(递归时为子数组)相邻元素的最大和*/

float get_max_sum (int l, int u)

{  

int i, m;

float lmax, rmax, sum;

 

/* 子数组内没有任何元素 */

    if (l > u) { 

       return 0;

}

 

/*子数组内仅有一个元素*/

    if (l == u) {

       return max(0, x[l]); /*此时只需返回0x[l]中大的一个即可*/

}

  

m = (l + u) / 2; /*求中间值,为折半求和准备*/

   

/*开始折半求和*/

/* 先求m左侧子数组x[l, m](m)的最大和*/

    lmax = sum = 0;

    for (i = m; i >= l; i--) {

       sum += x[i];

       if (sum > lmax) {

           lmax = sum; /*通过不断的比较以获取左侧的最大和*/

}

    }

   

/* 再求右侧子数组xm, u]中的(不含m)最大和*/

    rmax = sum = 0;

    for (i = m + 1; i <= u; i++) {

       sum += x[i];

       if (sum > rmax) {

           rmax = sum; /*通过不断的比较以获取右侧的最大和*/

}

}

 

    return max(lmax + rmax,

       max(recmax(l, m), recmax(m+1, u)));

/*实际就是求各个子数组的最大和:

  左右的并集,m的左侧和m的右侧三个最大和,

  注意求左右侧最大和时又进一步进行递归求和。

*/

}

 

int main()

{

    float max_sum;

 

while (scanf("%d", &n) != EOF) {

 

   /*初始化数组*/   

       sprinkle();

 

       max_sum = get_max_sum();

 

printf (“max sum = %f/n”, max_sum);

   }

    return 0;

}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值