草庐IT

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

瓦特的代码小屋 2024-04-22 原文

编译环境:Dev-C++

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


最大字段和问题描述:

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

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


算法思想

(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];

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

这个时候分成三种情况:

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

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

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

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


(4)动态规划法:

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

 

定义一个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 

 

可以看到,通过一步步简化,时间复杂度从O(n^3)到O(n^2)到O(nlogn)再到O(n),时间复杂度不断改进,这就是算法的魅力! 


源代码:

#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语言)的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

  3. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  4. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

  5. ruby - 通过 RVM (OSX Mountain Lion) 安装 Ruby 2.0.0-p247 时遇到问题 - 2

    我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search

  6. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  7. ruby - Fast-stemmer 安装问题 - 2

    由于fast-stemmer的问题,我很难安装我想要的任何ruby​​gem。我把我得到的错误放在下面。Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingfast-stemmer:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcreatingMakefilemake"DESTDIR="cleanmake"DESTDIR=

  8. ruby - 安装 Ruby 时遇到问题(无法下载资源 "readline--patch") - 2

    当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub

  9. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  10. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

随机推荐