最大子段和
来源:互联网 发布:ithink系统动力学软件 编辑:程序博客网 时间:2024/05/17 23:51
问题描述:
给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整均为负数时定义子段和为0,依此定义,所求的最优值为: Max{0,a[i]+a[i+1]+…+a[j]},1<=i<=j<=n。
自上而下的分治算法:
将序列a[1:n]分解为长度相等的2段a[1:n/2],和a[n/2+1, n],分别求出这2个字段的和,与a[1:n]的最大字段和相比,有三种情况会出现:
1. a[1:n/2]与a[1:n]的最大子段和相同 <=> 最大字段在前半部分
2. a[n/2+1, n]与a[1:n]的最大子段和相同 <=> 最大子段在后半部分
3. a[1:n]的最大子段和为越过中点n/2,这种情况下a[n/2]和a[n/2+1]在最优子序列中,在[i,n/2]找到最大值S1,在[n/2+1,j]中找到最大值S1,所求最优值为S1+S2,最优序列为i->j。
源程序代码:
#include<iostream>#include<cstdlib>#include<cstdio>#define MAX 10010using namespace std;int MaxSubSum(int *a, int left, int right){ int sum = 0; if(left == right)//当该段至于一个元素时候,负数舍弃 sum = a[left]>0?a[left]:0; else { int mid; mid = (right + left)/2 ; int leftsum = MaxSubSum(a, left, mid);//求左段的最大子段和 int rightsum = MaxSubSum(a, mid+1, right);//求右段的最大子段和 /*第三种情况下的左方最大子段和*/ int s1 = 0; int lefts = 0; for(int i=mid; i>=left; i--) { lefts+=a[i]; if(lefts>s1) s1 = lefts; } /*第三种情况下的右方最大子段和*/ int s2=0; int rights=0; for(int i=mid+1; i<=right; i++) { rights += a[i]; if(rights>s2) s2 = rights; } sum = s1+s2; if(sum<leftsum) sum = leftsum; if(sum<rightsum) sum = rightsum; } return sum;}int main(){ int num; int sequence[MAX]; int ANS; cout<<"输入序列的个数:"; cin>>num; cout<<"请输入序列的各数字"<<endl; for(int i=0; i<num; i++) { cin>>sequence[i]; } cout<<MaxSubSum(sequence, 0, num-1)<<endl; return 0;}
动态规划算法:
根据分治法,分析左右子段s1,s2与原序列最优值之间的关系,需要知道段与子段之间最优值的递归关系。对所求的最大子段有如下关系:
二维表示的左端i,右端j转化为一维的表示b[j],左端j,利于降低算法复杂性。
根据b[j]的定义,他表示 [i,j] (1《 i《j )连续范围内序列和的最大值,有:
当b[j-1]>0时,b[j]=b[j-1]+a[j],
当b[j-1]<=0时,b[j] = a[j];
综上所述得到递归方程:
源程序代码:
#include<iostream>#include<cstdio>#include<cstdlib>#define maxn 5000using namespace std;FILE *fp, *fp1; int a[maxn], b[maxn];int MaxSum(int n, int a[], int *l, int *r){ int sum = 0; int bb=0; *l = 0; *r = 0; for(int i=0; i<n; i++) { if(bb>0) { bb+=a[i]; } else { bb=a[i]; *l=i; } if(bb>sum) { sum = bb; *r = i; } } return sum;}int main(){ fp = fopen("附件2.最大子段和输入数据2017-序列1.txt","r"); fp1 = fopen("附件2.最大子段和输入数据2017-序列2.txt","r"); int count = 0, count1=0; int l1=0, r1=0; int l2=0, r2=0; while(!feof(fp)) { fscanf(fp, "%d", &a[count]); count++; } while(!feof(fp1)) { fscanf(fp1, "%d", &b[count1]); count1++; } cout<<"序列1的最大子段和为:"; cout<<MaxSum(count, a, &l1, &r1); cout<<"序号为"<<l1<<"至"<<r1<<endl; cout<<"序列2的最大子段和为:"; cout<<MaxSum(count, b, &l2, &r2); cout<<"序号为"<<l2<<"至"<<r2<<endl; return 0;}
阅读全文
0 0
- 最大子段和
- 最大子段和
- 最大子段和
- 最大子段和
- “最大子段和”
- 最大子段和
- 最大子段和
- 最大子段和
- 最大子段和
- 最大子段和
- 最大子段和
- 最大子段和
- 最大子段和
- 最大子段和
- 最大子段和
- 最大子段和
- 最大子段和
- 最大子段和
- Java读取txt
- C++程序员学Java系列之四:Java中的关键字和标识符
- Maven 文件错误Failure to transfer org.codehaus.plexus:plexus-io:pom:1.0,Failure to transfer org.codehaus
- 九度1090-路径打印-多叉树
- Cmake编译安装MySQL完整版
- 最大子段和
- ubuntu ssh git访问验证
- RecyclerView 的简单使用
- highcharts 饼图
- [LeetCode] Insert Delete GetRandom O(1)
- python 元组
- USACO 3.3.2
- tcp/ip面试
- iOS开发中的单例模式