最大子段和问题算法设计(C语言)

这篇具有很好参考价值的文章主要介绍了最大子段和问题算法设计(C语言)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

编译环境:Dev-C++

分别用暴力枚举,优化枚举,递归分治和动态规划的方法解决最大字段和问题。


最大字段和问题描述:

给定n个整数(可能为负整数)组成的序列a1,a2,…,an,求该序列连续的子序列和的最大值。 如果该子段的所有元素和是负整数时定义其最大子段和为0。

最大子段和问题的形式化描述:

最大子段和问题算法设计(C语言)


算法思想

(1)暴力枚举法思想:

用一个三重循环,i和j从1到n分别表示每一次加法加数和最后一个被加数的下标,k从i到j用来做a[i]到a[j]求和,每次循环加和定义一个当前最大子段和thissum和sum比较替换;


(2)优化枚举法思想:

在暴力枚举下,我们很容易想到可以把k这一重循环省略,避免了重复加和,例如:要求sum[3,8],只需要在sum[3,7]的基础上加a[8],而不需要再从a[0]加到a[8],从而提高效率。


(3)分治法思想:

将原数组a[left,right]分为长度相同的两段子数组a[left,mid]和a[mid+1,right];

然后利用递归分别求解左半段和又半段的最大子段和;

这个时候分成三种情况:

第一种情况是:最大子段和为左半段最大字段和;

第二种情况是:最大子段和为右半段最大字段和;

第三种情况是:跨中间的最大字段和;求解思想见下图: 

最大子段和问题算法设计(C语言)

最后把三种情况的最大子段和做比较就可以得出最大子段和。


(4)动态规划法:

之所以用到了动态规划的思想,是因为问题具有最小子结构性质,而且子问题之间有所重复,原问题的最优解可以由此问题从底向上推导出来

最大子段和问题算法设计(C语言)  

定义一个f数组复制a数组,f[i]表示以a[i]为结束的子数组最大和,f[i]一定是包涵a[i]的,所以如果前面的子问题最优解是小于0,那么包涵以a[i]为结尾的最大字段和,就是它自己,而如果前面的子问题最优解大于或者等于0,则把a[i]加上f[i-1]就是他的最大子段和;  


 算法调试过程及输入输出结果:

测试用例:

Input:

      7

      1 -5 2 4 5 -1 7

Output:

      17

      2 4 5 -1 7 

 最大子段和问题算法设计(C语言)

可以看到,通过一步步简化,时间复杂度从O(n^3)到O(n^2)到O(nlogn)再到O(n),时间复杂度不断改进,这就是算法的魅力! 文章来源地址https://www.toymoban.com/news/detail-407571.html


源代码:

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
/*测试用例:

Input:
	7 
	1 -5 2 4 5 -1 7
Output:
	17
	2 4 5 -1 7
	 
*/ 
//暴力枚举法
int MaxSubSum_Violent(int *a,int n,int& besti,int& bestj){
    int sum=0;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
                int thissum=0;
            for(int k=i;k<=j;k++){
                thissum+=a[k];
            }
        if(thissum>sum){
            sum=thissum;
            besti=i;
            bestj=j;
        }
        }
    }
    return sum;
}
//优化枚举法
int MaxSubSum_Optimized(int *a,int n,int &besti,int &bestj){
    int sum=0;
    for(int i=0;i<n;i++){
            int thissum=0;
        for(int j=i;j<n;j++){
                thissum+=a[j];

        if(thissum>sum){
            sum=thissum;
            besti=i;
            bestj=j;
        }
        }
    }
    return sum;
}
//分治法
int CrossSubArray(int *a,int left,int mid,int right){
    int leftsumMax=0,rightsumMax=0,temp=0;;
    for(int i=mid;i>=left;i--){
        temp+=a[i];
        if(temp>=leftsumMax){
            leftsumMax=temp;
        }
    }
    temp=0;
    for(int j=mid+1;j<=right;j++){
        temp+=a[j];
        if(temp>=rightsumMax){
            rightsumMax=temp;
        }
    }
    int crosssum=leftsumMax+rightsumMax;
    return crosssum;

}
int MaxSubSum_DivideConquer(int *a,int left,int right){
    int sum=0;
    if(left==right){
        sum=a[left];
    }else{
        int mid=(left+right)/2;
        int leftsum=MaxSubSum_DivideConquer(a,left,mid);
        int rightsum=MaxSubSum_DivideConquer(a,mid+1,right);
        int crosssum=CrossSubArray(a,left,mid,right);
        if(leftsum>=rightsum&&leftsum>=crosssum){
            sum=leftsum;
        }else if(rightsum>=leftsum&&rightsum>=crosssum){
            sum=rightsum;
        }else if(crosssum>=rightsum&&crosssum>=leftsum){
            sum=crosssum;
        }
    }
    return sum;
}
//动态规划
int MaxSubSum_DynamicProgram(int *a,int n){
    int Max_sum=0;
    int *f=(int *)malloc(sizeof(int)*(n+1));
    for(int i=0;i<n;i++){
    	f[i]=a[i];
	}
	for(int i=1;i<=n;i++){
		if(f[i-1]+a[i]>=a[i]) f[i]=f[i-1]+a[i];
		if(f[i-1]+a[i]<a[i]) f[i]=a[i];
		if(f[i]>=Max_sum) Max_sum=f[i];
	}
//    for(int i=1;i<=n;i++){
//        if(f[i-1]>=0) f[i]=f[i-1]+a[i];
//        if(f[i-1]<0) f[i]=a[i];
//        if(f[i]>=Max_sum) Max_sum=f[i];
//    }
    return Max_sum;
}
int main(){
    int n=0;
    printf("请输入原数组的长度:");
    scanf("%d",&n);
    int *a=(int*)malloc(sizeof(int)*(n+1));
    if(!a) exit(-2);
    puts("请输入原数组:");
    for(int i=0;i<n;i++){
        scanf("%d",a+i);
    }
    int besti,bestj;
    puts("使用暴力枚举法的结果是");
    printf("最大子段和为:%d\n",MaxSubSum_Violent(a,n,besti,bestj));
    puts("对应的子数组为:");
	for(int i=besti;i<=bestj;i++){
		printf("%d ",a[i]);
	} 
	putchar('\n');
    puts("--------------------------------");
    puts("使用优化枚举法的结果是");
    printf("最大子段和为:%d\n",MaxSubSum_Optimized(a,n,besti,bestj));
    puts("对应的子数组为:");
	for(int i=besti;i<=bestj;i++){
		printf("%d ",a[i]);
	} 
	putchar('\n');
    puts("--------------------------------");
    puts("使用分治法的结果是");
    printf("最大子段和为:%d\n",MaxSubSum_DivideConquer(a,0,n));

    puts("--------------------------------");
    puts("使用动态规划法的结果是");
    printf("最大子段和为:%d\n",MaxSubSum_DynamicProgram(a,n));

}

到了这里,关于最大子段和问题算法设计(C语言)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 中北大学算法分析与设计实验报告六(最大团问题)

    1.实验名称 实验六 回溯与分支限界算法实验 2.实验目的 题目:最大团问题 强化学生利用回溯算法和优化处理实际问题的能力。 3.训练知识点集群 (1)根据实验内容设计算法伪代码进行算法描述; (2)利用C++/C/Java等编程语言对算法伪代码进行工程化实现; (3)输入测试用

    2024年02月06日
    浏览(42)
  • 【MyBatis 学习三】子段不一致问题 && 多表查询 && 动态SQL

    目录 一、解决Java实体类属性与数据库表字段不一致问题 🌷现象1:显示字段不对应:使用ResultType查询结果为null; 🌷解决办法:字段不对应:使用ResultMap解决。 二、数据库的多表查询 🌷方式1:使用对象user  🌷方式2:直接写具体的属性 三、动态SQL的使用 🌷1、if标签:单

    2024年02月15日
    浏览(39)
  • C语言经典算法之Euclidean算法求最大公约数

    目录 前言 A.建议 B.简介 一 代码实现 二 时空复杂度 A.循环实现 a.时间复杂度(Time Complexity): b.空间复杂度(Space Complexity): B.递归实现 a.时间复杂度(Time Complexity): b.空间复杂度(Space Complexity): 三 优缺点 A.循环实现 a.优点: b.缺点: c.总结: B.递归实现 a.优点:

    2024年03月26日
    浏览(55)
  • 【算法奥义】最大矩形问题

    下面展示 cpp代码 。

    2024年02月10日
    浏览(44)
  • C语言—求最大公约数(4种算法思路)

    如果大数可以整除小数,那么最大公约数为小数。如果不能整除小数,那么这两个数就按大到小依次对比小数小的数求余,遇到都能够整除的,就是最大公约数。 用a对b求余,若余数为0,则除数b为最大公约数。若余数不为0,将此余数r作为新的除数,b作为新的被除数,重新

    2024年04月13日
    浏览(39)
  • 【最大流】Ford-Fulkerson算法——算法设计与分析

    给定有向图 G = V , E , C G=V,E,C G = V , E , C ,其被称为流网络: 容量: ∀ e ∈ E , c ( e ) ≥ 0 forall e in E, c(e) ge0 ∀ e ∈ E , c ( e ) ≥ 0 流量: ∀ e ∈ E , 0 ≤ f ( e ) ≤ c ( e ) forall e in E, 0 leq f(e) leq c(e) ∀ e ∈ E , 0 ≤ f ( e ) ≤ c ( e ) 剩余容量: ∀ e ∈ E , c ( e ) − f ( e ) forall

    2024年02月04日
    浏览(29)
  • python使用贪心算法求最大整数问题

    对于使用贪心算法的一个比较经典的问题,主要是为了解决最大整数的拼接问题,如果给定一个列表,这个列表中所包括的是一些非负整数,如果对这些整数进行组合,怎样才能组合出一个最大的整数,这里要注意一个问题,有可能整数过大会导致出现溢出的现象,所以返回

    2024年01月19日
    浏览(42)
  • 增广路算法 DFS求解 最大网络流问题

    最大网络流问题是这样的,有一个有向图,假定有一个源点,有一个汇点,源点有流量出来,汇点有流量进入,有向图上的边的权重为该条边可通过的最大流量(方向为边的方向),问从源点到汇点这条路径上,可以通过的流量总和最大是多少?注意并不一定是只有一条路径,

    2024年01月21日
    浏览(43)
  • VSCode配置C语言编译环境

    一、下载C语言编译器: (1)下载地址:MinGW-w64 - for 32 and 64 bit Windows - Browse /mingw-w64 at SourceForge.net 下载如下的windows版本:  (2)配置环境变量:  二、安装VSCode 三、配置VSCode (1)安装C/C++插件:  (2)配置文件:新建.vscode文件夹,文件夹下新建如下三个文件  1、c_cpp_

    2024年02月10日
    浏览(47)
  • 【算法5.1】背包问题 - 01背包 (至多最大价值、至少最小价值)

    目录 至少模板和至多模板的两大区别 1、至多模板 2、至少模板 2. 01背包 - 至多模板 - 体积至多j,总价值最大 1、朴素做法 - 二维dp  2、优化 - 一维dp 4700. 何以包邮? - 至少模板 - 价值至少j,总价值最小   初始化不同 : 至多模板求的是最大值,所以初始化为f[0~m]=0 至少模

    2024年02月12日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包