最大子段和——用蛮力算法,分治策略,动态规划算法三种求法(C语言)

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

目录

一、题目

二、算法求解

1、蛮力算法

伪代码

 算法分析

程序

2、分治策略

伪代码

算法分析

程序

3、动态规划算法

伪代码

算法分析

程序


一、题目

设A=<a1,a2,...,an>是n个整数的序列,称<ai,....,aj>为该序列的连续子序列,其中1<=i<=j<=n,子序列的元素之和称为A的子段和:

例如,A=<-2,11,-4,13,-5,-2>,那么它的子段和如下:

长度为1的子段和有:-2,11,-4,13,-5,-2

长度为2的子段和有:9,7,9,8,-7

长度为3的子段和有:5,20,4,6

长度为4的子段和有:18,15,2

长度为5的子段和有:13,13

长度为6的子段和有:11

其中的最大子段和为:11-4+13=20

则最大子段和问题为:

给定n个整数的序列A=<a1,a2,...,an>,求

最大子段和问题的动态规划算法,算法与数据结构,动态规划,算法,c语言,数据结构,策略模式

二、算法求解

1、蛮力算法

通过枚举A的所有连续子序列并且求和,通过比较找出具有最大和的子序列。

伪代码

//算法 Enumerate
//输入:数组A[1..n]
//输出:sum,first,last   //sum为最大子段和,first与last分别是和的首末位置

  1.      
  2.                
  3.               
  4.      
  5.      
  6.                
  7.                

 算法分析

3个for循环,每次执行O(n)次,循环内部是常数操作,所以该算法的时间复杂度为

程序

//算法3.8 Enumerate
//输入:数组A[1..n]
//输出:sum,first,last

#include<stdio.h>
#include<stdlib.h>
void Enumerate (int a[],int n)
{
	int sum = 0;
	int i,j,k;
	int first,last;
	for(i = 0;i < n; i++){
		for(j = i;j < n;j++){
			int thissum = 0;
			for(k = i;k <= j; k++){
				thissum = thissum + a[k];
			}
			if(thissum > sum){
				sum = thissum;
				first = i;
				last = j;
			}
		}
	}
	printf("数组A的最大连续子段和为A[%d..%d]=%d",first+1,last+1,sum);
}

int main()
{
	int A[6]={-2,11,-4,13,-5,-2};
	int i;
	for(i = 0;i < 6;i++)
	{
		printf("%d ",A[i]);
	}
	printf("\n");
	Enumerate(A,6); 
	return 0;
}

2、分治策略

与最邻近点对的算法(参考之前的文章)类似,我们可以在 n/2的位置将 A 划分成A1和 A2前后两半,于是 A 的最大子段和可能是三种情况:

  1. 出现在 A1部分
  2. 出现在 A 部分,
  3. 出现在横跨两边的中间部分

前两种情况恰好对应于两个规模减半的子问题,第三种情况需要特殊处理一下,设原问题的输人是 A [1...n],中间分点 k = n /2,那么前半部分子问题的输人是 A [1...k],后半部分子问题的输人是 A [ k +1,n]。在第三种情况下,设这个最大和是 A [ p .. q ],那么, 最大子段和问题的动态规划算法,算法与数据结构,动态规划,算法,c语言,数据结构,策略模式,从 A [ p ]到 A [ k ]的元素都在 A1 中,从 A [ k 十1]到 A [ q ]的元素都在 A2 中,我们只需要从 A [ k ]和 A [ k +1]分别向前和向后求和即可,比如以 A [ p ...k ]的计算为例,依次计算 A [ k .. k ], A [ k-1, k ],.., A [1...k],记下其中最大的和 S1 ,即 A [ p ... k ],对右半部可以同样处理,只不过扫描方向相反,得到的 S2 就是 A [ k+1... q ]的元素之和,当两个方向的扫描都完成之后,S1+S2 就是横跨中心的最大和,其边界从p到q。这三种情况都计算完成以后,通过比较就可以确定 A 的最大子段和

最大子段和问题的动态规划算法,算法与数据结构,动态规划,算法,c语言,数据结构,策略模式

伪代码

//MaxSubSum(A,left,right) 【分治算法】
//输入:数组A,left,right分别是A的左右边界,1<=left<=right
//输出:A的最大子段和sum及其子段的前后边界

  1. 最大子段和问题的动态规划算法,算法与数据结构,动态规划,算法,c语言,数据结构,策略模式
  2. 最大子段和问题的动态规划算法,算法与数据结构,动态规划,算法,c语言,数据结构,策略模式
  3. 最大子段和问题的动态规划算法,算法与数据结构,动态规划,算法,c语言,数据结构,策略模式
  4. 最大子段和问题的动态规划算法,算法与数据结构,动态规划,算法,c语言,数据结构,策略模式

算法分析

设算法对规模为的输人运行时间是 T ( n ),行3和行4是递归调用,每个子问题是原来问题规模的一半,因此需要2T( n /2)时间,行5和行6的处理需要扫描A的每个元素,总计需要O(n)时间,于是递归方程为:

最大子段和问题的动态规划算法,算法与数据结构,动态规划,算法,c语言,数据结构,策略模式

该方程的解为:

程序

//算法3.9 MaxSubSum(A,left,right) 【分治算法】 
//输入:数组A,left,right分别是A的左右边界,1<=left<=right
//输出:A的最大子段和sum及其子段的前后边界

#include<stdio.h>
#include<stdlib.h>

typedef struct max_info{
	int low;
	int high;
	int sum;
};

struct max_info MaxSubSum(int a[],int left,int right)
{
	struct max_info maxinfo;
	maxinfo.sum = 0;
	int i;
	if(left == right){
		maxinfo.sum = a[left]>0 ? a[left] : 0;
		maxinfo.high = right;
		maxinfo.low = right;
		return maxinfo;
	}
	else{
		
		struct max_info leftinfo;//左侧 
		struct max_info rightinfo;//右侧 
		struct max_info croseinfo;//跨越 
		
		
		int center = (left + right) / 2;
		leftinfo = MaxSubSum(a, left, center);
		rightinfo = MaxSubSum(a, center + 1, right);
		
		
		int s1 = 0;
		int suml = 0;
		for(i = center; i >= left; i--)
		{			
			suml += a[i];
			if(suml > s1) 
			{
				s1 = suml;
				croseinfo.low = i;
			}	
		}
	
		int s2 = 0;
		int sumr = 0;
		for(i = center + 1; i < right; i++)
		{			
			sumr += a[i];
			if(sumr > s2)
			{
				s2 = sumr;
				croseinfo.high = i;	
			}	

		}
		croseinfo.sum = s1 + s2;
		if(croseinfo.sum < leftinfo.sum){
			maxinfo.sum = leftinfo.sum;	
			maxinfo.high = leftinfo.high;
			maxinfo.low = leftinfo.low;
		} 			
		if(croseinfo.sum < rightinfo.sum){
			maxinfo.sum = rightinfo.sum;
			maxinfo.high = rightinfo.high;
			maxinfo.low = rightinfo.low;
		} else{
			maxinfo.sum = croseinfo.sum;
			maxinfo.high = croseinfo.high;
			maxinfo.low = croseinfo.low;
		}
			
	}
	return maxinfo;
}

int main()
{
	struct max_info maxinfo;
	int A[6]={-2,11,-4,13,-5,-2};
	int i;
	for(i = 0;i < 6;i++)
	{
		printf("%d ",A[i]);
	}
	printf("\n");
	maxinfo = MaxSubSum(A,0,5); 
	printf("数组A的最大连续子段和为:A[%d..%d]=%d\n",maxinfo.low+1,maxinfo.high+1,maxinfo.sum);
	return 0;
}

3、动态规划算法

为了得到更高效的算法,我们需要在子问题之间建立一个简单的递推关系,因此定义一个优化函数

最大子段和问题的动态规划算法,算法与数据结构,动态规划,算法,c语言,数据结构,策略模式

 对于数组A=<2,-5,8,11,-3,4,6>,其优化函数为:C[1]=2、C[2]=-3、C[3]=8、C[4]=19、C[5]=16、C[6]=20、C[7]=26

在这种优化函数中,C [ i +1]可以通过 C[ i ] 直接得到,因为如果 A [1...  i +1 ]的子段 A [ k .. i +1]是使得 C [ i +1 ]达到最大和的子段,那么 A [ k ... i ]一定是使得 C [ i ]达到最大和的子段.如若不然,存在一个使得 C[ i ]达到更大和的子段 A [ t ... i ],那么在 A [ t ... i ]后面加上 A[ i+1 ]所得到的子段 A [ t ... i +1]之和将大于 C [ i +1].这与 C [ i 十1]是 A [1.. i +1]以元素 A [ i +1]作为最后元素的最大子段和矛盾.这恰好验证了这样定义的优化函数满足优化原则于是,我们在考虑怎样选择才能使得 C [ i +1]达到最大值时,只要考虑一个问题:是否需要把 C [ i ]加到 A [ i +1上?而这取决于 C [ i ]是否大于0.

那么递推关系为:

最大子段和问题的动态规划算法,算法与数据结构,动态规划,算法,c语言,数据结构,策略模式

     若A[1]>0,否则C[1]=0

根据上面的递推公式,得到C[1],C[2],C[3].....C[n,]恰好枚举了以任何元素为最后元素的所有子段的最大和,我们要找到所求问题的最大子段和,就要对上面n个子段和进行比较,找到其中最大和。

伪代码

//MaxSum(A,n) 【动态规划】
//输入:数组A
//输出:最大子段sum,子段的最后位置c

  1.       
  2.        最大子段和问题的动态规划算法,算法与数据结构,动态规划,算法,c语言,数据结构,策略模式
  3.       
  4.       
  5.       
  6.                    

算法分析

MaxSum(A,n) 算法只有一个for循环,执行次数为O(n),循环体内都是常数次运算,因此算法复杂度为O(n)文章来源地址https://www.toymoban.com/news/detail-820951.html

程序

//算法3.10 MaxSum(A,n) 【动态规划】 
//输入:数组A
//输出:最大子段sum,子段的最后位置c

#include<stdio.h>
#include<stdlib.h>

void MaxSum(int A[], int n)
{
	int sum = 0;
	int b = 0;
	int i,c;
	for(i = 0;i < n;i++)
	{
		if(b > 0)
			b= b+A[i];
		else
			b = A[i];
		
		if(b > sum)
		{
			sum = b;
			c = i;
		}
	}
	printf("数组A的最大连续子段和为:%d,且子段最后位置为:%d",sum,c+1);
} 

int main()
{
	int A[7]={2,-5,8,11,-3,4,6};
	int i;
	for(i = 0;i < 7;i++)
	{
		printf("%d ",A[i]);
	}
	printf("\n");
	MaxSum(A,7); 
	return 0;
}

到了这里,关于最大子段和——用蛮力算法,分治策略,动态规划算法三种求法(C语言)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 矩阵乘法的三种算法(蛮力嵌套循环法,分治递归法,Strassen法)

    目录 一.矩阵乘法的嵌套循环算法 二.矩阵乘法的递归算法 三.矩阵乘法的Strassen算法 一.矩阵乘法的嵌套循环算法 伪代码: C++代码: 二.矩阵乘法的递归算法 伪代码: C++代码: 原理:矩阵乘法的分块运算: 【2.5】矩阵分块相乘 - 知乎 (zhihu.com) 复杂度: 三.矩阵乘法的Strass

    2024年02月13日
    浏览(26)
  • 分治法解二维的最近对问题,算法分析与代码实现,蛮力法与分治法解决二维的最近对问题的区别

    🎊【数据结构与算法】专题正在持续更新中,各种数据结构的创建原理与运用✨,经典算法的解析✨都在这儿,欢迎大家前往订阅本专题,获取更多详细信息哦🎏🎏🎏 🪔本系列专栏 -  数据结构与算法_勾栏听曲_0 🍻欢迎大家  🏹  点赞👍  评论📨  收藏⭐️ 📌个人主

    2024年02月04日
    浏览(29)
  • 求最大字段和(穷举法、动态规划、分治法)

    1、案例要求 给定由n个整数(可能为负整数)组成的序列a1,a2,…,an,求该序列形如: 的子段和的最大值。当所有整数均为负数时定义其最大子段和为0。 分别采用穷举法、分治法、动态规划法完成。 2、算法设计与实现 2.1 穷举法 2.1.1 算法设计思路 通过定义遍历子段起始位置

    2024年02月02日
    浏览(42)
  • 力扣 53. 最大子数组和(C语言+分治递归、动态规划)

            给你一个整数数组  nums  ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组  是数组中的一个连续部分。         示例 1:         示例 2:         示例 3: (1)分治递归         分治法的核心部分。

    2024年02月07日
    浏览(31)
  • 【LeetCode: 53. 最大子数组和 | 暴力递归=>记忆化搜索=>动态规划 | 分治法 】

    🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,CSDN-Java领域新星创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文

    2023年04月21日
    浏览(58)
  • 算法 || 分治法【查找最大元素和次大元素)】 #01

    对于给定的含有n元素的无序序列,求这个序列中最大和次大的两个不同的元素。例如:(2, 5, 1, 4, 6, 3),最大元素为6,次大元素为5。 【在无序数组a[low…high]中找到第一大和第二大的数。两数不同。】 采用 折半 的方式,采用分治法求解。 分解: 情况1 ,如果数组a[low…

    2023年04月09日
    浏览(64)
  • 南京邮电大学算法与设计实验一:分治策略(最全最新,与题目要求一致)

    实验原理: 1、用分治法实现一组无序序列的两路合并排序和快速排序。要求清楚合并排序及快速排序的基本原理,编程实现分别用这两种方法将输入的一组无序序列排序为有序序列后输出。 2、采用基于“五元中值组取中值分割法”(median-of-median-of-five partitioning)的线性时

    2024年04月17日
    浏览(70)
  • 算法分析与设计---分治+动态规划

    1.分治法 适用条件: 问题规模缩小到一定程度容易求解 问题可以分解为若干个规模较小的 相同 子问题,即问题具有最优子结构( 使用分治法前提 ) 可以利用子问题的解合并为该问题的解( 决定是否使用分治法 ) 各个子问题 相互独立 ,即子问题之间不包含公共子问题(

    2024年02月07日
    浏览(32)
  • 四大算法:贪心、分治、回溯、动态规划

    贪心算法(又称贪婪算法),在求解问题时,总是做出在当前看来是最好的选择。也就是说,不从整体最优解进行考虑,而是得到某种意义上的局部最优解。 贪心算法采用自顶向下,以迭代的方法做出贪心选择,每做一次贪心选择,就将所求问题简化为一个规模更小的问题。

    2024年02月15日
    浏览(29)
  • 探索经典算法:贪心、分治、动态规划等

    贪心算法是一种常见的算法范式,通常在解决最优化问题中使用。 贪心算法是一种在每一步选择中都采取当前状态下最优决策的算法范式。其核心思想是选择每一步的最佳解决方案,以期望达到最终的全局最优解。这种算法特点在于只考虑局部最优解,而不会回溯或重新考虑

    2024年02月05日
    浏览(30)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包