最大子段和问题
2016-05-22 14:35
387 查看
问题情境:
给定n个整数(有可能是负数)组成的序列,要求分别用蛮力法,减治法和动态规划法,求最该序列的最大子段和,并对它们的效率进行比较分析。蛮力法:
也称穷举法或枚举法,是一种简单直接地解决问题的方法,常常基于问题的描述,所以,蛮力法也是最容易应用的方法。它依赖的基本技术是遍历,采用一定的策略依次处理待求解问题的所有元素,从而找出问题的解。减治法:
将原问题分解为若干个子问题,并且原问题的解与子问题的解之间存在某种确定的关系,这种关系通常表现为:1)原问题的解只存在于其中一个较小规模的子问题中;
2)原问题的解与其中一个较小规模的解之间存在某种对应关系。
动态规划法:
动态规划法将待求解问题分解成若干个相互重叠的子问题,每个子问题对应决策过程的一个阶段,一般来说,子问题的重叠关系表现在对给定问题求解的递推关系(称动态规划函数)中,将子问题的解求解一次并填入表中,当需要再次求解此子问题时,可以通过查表获得该子问题的解,从而避免了大量重复计算。求解过程:
1)划分子问题:将原问题分解为若干个子问题,每个子问题对应一个决策阶段,并且子问题之间具有重叠关系。
2)确定动态规划函数:根据子问题之间的重叠关系找到子问题满足的递推关系式(即动态规划函数),这是关键。
3)填写表格:设计表格,以自底向上的方式计算各个子问题的解并填表,实现动态规划过程。
代码实践:
#include<iostream> #include<time.h> #include<Windows.h> using namespace std; #define MAX 10000 //蛮力法 int BF_Sum(int a[],int n) { int max=0; int sum=0; int i,j; for(i=0;i<n-1;i++) { sum=a[i]; for(j=i+1;j<n;j++) { if(sum>=max) { max=sum; } sum+=a[j]; } } return max; } //分治法 int maxSum1(int a[],int left,int right) { int sum=0; if(left==right) //如果序列长度为1,直接求解 { if(a[left]>0) sum=a[left]; else sum=0; } else { int center=(left+right)/2; //划分 int leftsum=maxSum1(a,left,center); int rightsum=maxSum1(a,center+1,right); int s1=0; int lefts=0; for(int i=center;i>=left;i--) { lefts+=a[i]; if(lefts>s1) s1=lefts; } int s2=0; int rights=0; for(int j=center+1;j<=right;j++) { rights+=a[j]; if(rights>s2) s2=rights; } sum=s1+s2; if(sum<leftsum) sum=leftsum; if(sum<rightsum) sum=rightsum; } return sum; } //动态规划法 int DY_Sum(int a[],int n) { int sum=0; int *b=(int*)malloc(n*sizeof(int)); b[0]=a[0]; for(int i=1;i<n;i++) { if(b[i-1]>0) b[i]=b[i-1]+a[i]; else b[i]=a[i]; } for(int j=0;j<n;j++) { if(b[j]>sum) sum=b[j]; } delete []b; return sum; } //主函数 int main() { int num[MAX]; int i; const int n=40; LARGE_INTEGER begin, end,frequency; QueryPerformanceFrequency(&frequency); cout<<"生成随机序列:"; srand(time(0)); for(i=0;i<n;i++) { if(rand()%2==0) num[i]=rand(); else num[i]=(-1)*rand(); if(n<100) cout<<num[i]<<" "; } cout<<endl; cout<<"\n蛮力法:"<<endl; cout<<"最大字段和:"; QueryPerformanceCounter(&begin); cout<<BF_Sum(num,n)<<endl; QueryPerformanceCounter(&end); cout<<"时间:"<<(double)(end.QuadPart-begin.QuadPart)/frequency.QuadPart<<"s"<<endl; cout<<"\n分治法:"<<endl; cout<<"最大字段和:"; QueryPerformanceCounter(&begin); cout<<maxSum1(num,0,n)<<endl; QueryPerformanceCounter(&end); cout<<"时间:"<<(double)(end.QuadPart-begin.QuadPart)/frequency.QuadPart<<"s"<<endl; cout<<"\n动态规划法:"<<endl; cout<<"最大字段和:"; QueryPerformanceCounter(&begin); cout<<DY_Sum(num,n)<<endl; QueryPerformanceCounter(&end); cout<<"时间:"<<(double)(end.QuadPart-begin.QuadPart)/frequency.QuadPart<<"s"<<endl; system("pause"); return 0; }
运行结果:
相关文章推荐
- OpenCV人脸检测
- Spring实现AOP的4种方式(转)
- Debug---调试
- 【LeetCode】50. Pow(x, n)
- SD卡,SharedPreference以及Pull解析
- JAVA多线程(一)基本概念和上下文切换性能损耗
- Linux文件属性
- Java内存区域分布
- 实践二——内核模块
- 三本计算机科学的书
- PAT小试牛刀1043输出PATest
- 1793 良序字串
- Android RelativeLayout和LinearLayout性能分析
- 灰度梯度共生矩阵纹理特征
- Duilib教程-HelloDuilib及DuiDesigner的简单使用
- 【名词】JPA、JTA、JMS、CRUD的解释
- scala中val function
- linux+weblogic Too many open files解决方案
- 如何在Android中实现全屏,去掉标题栏效果
- unix中的线程池技术详解