目录
实验目的
1 理解全局求解与局部划分的思想;
2 理解分治法\减治法的分解思想;
3 理解分治与减治的区别与联系;
4 理解递归与非递归和各种算法区别与联系。
实验内容
1 一维最近对问题 (蛮力法、分治法、减治法)
2 最大子段和问题(蛮力法、分治法、动态规划法)
我的分析
1.一维最近对问题:
目的:在一维数轴上,找到相邻最近点对的距离。
思路:用三种方式求解,蛮力法、分治法和减治法。首先来说一下蛮力法的思路,蛮力法,顾名思义,就是很蛮力,我们直接别求解所有相邻点对的距离,找到最近点对。分治法的话,将数的区间分成大致相等的两部分,最近点对出现的的位置有三种情况,第一种在前半区,第二种在后半区,第三种就是一个点在前半区,一个点在后半区,结合这三种情况分析后即可得出答案。减治法的话,常用为减半治,我们们第一时间想到的便是减半治,最后两个点距离求出来,和前n-1个点的最短距离相比较,得出最近点对,要注意的是,采用蛮力法、分治法和减治法的时候需要将数组按照顺序排列。
2.最大字段和问题:
目的:求解给出数值的数组中,在连续的区间内和最大的字段。
思路:这题咱们采用蛮力法、分治法和动态规划法三种思路。首先来讲一下蛮力法的思路,利用双层循环遍历所有的字段的情况,每次将最大字段的值保存在max中,遍历完所有的字段之后即为最大字段。分治法:将字段分成大小差不多的两个区间,最大字段出现的情况有三种,一种是前半段区间,一种是后半段区间,一种是两段区间的和,利用递归不断的吧区间分为两部分,每次分完都对前半段、后半段求解,对前半段、后半段、前半段和后半段的和三个大小经行比较,最后即可得出结果。动态规划法:建立一个数组记录字段和,这里要注意,b[i]记录的是前i个数的最大字段和,所以当我们前i-1个字段为负数时,则直接从原数组开始即b[i]=a[i],最后在数组b中找到最大值即为字段和的最大值。
问题解决
- 一维最近对问题:
蛮力法:
算法描述:
算法:求最近对closePoint1()
输入:数组a
输出:最近对和最近对的大小。
过程:1、对数组经行顺序排列
2. 如果数组内数的个数<2 则无最近对
3.定义min保存最近对大小并初始化为a[1]-a[0]
4.定义长度为2的数组b记录两个点
5.定义循环变量i=1,i从1到a.length-1执行以下:
5.1. if(a[i+1]-a[i]<min){
min =a[i+1]-a[i];
b[0]=a[i];
b[1]=a[i+1];
}
算法实现:
运行结果:
时间复杂度:T(n)=O(n)
分治法:
算法描述:
算法:求最近对closePoint2()
输入:数组a,起始位置low,末位置high
输出:最近对大小。
过程:1.将数组里的数据按顺序排列。
2.如果只有一个元素返回0,如果只剩两个元素返回a[high]-a[low]
3.如果剩三个数:
int mid1=(high+low)/2;
int d11=a[mid1]-a[low];
int d12=a[high]-a[mid1];
return d11>d12? d12:d11;
4.求解前半区d1=closePoint2(a,low,mid)
5.求解后半区d2=closePoint2(a,mid+1,high)
6.求解中间区:d3=a[mid+1]-a[mid]
7.对d1、d2、d3经行比较返回最小值。
算法实现:
运行结果:
时间复杂度:O(n)
减治法:
算法描述:
算法求最近对:closePoint3()
输入:数组a
输出:最近对大小
过程:1、对数组经行有序排序
2.若只有一个数返回0
3.剩两个数的时候返回两个点距离。
4.减一治递归调用,比较最后一对与前n-1个点对的最近对大小,返回较小数即为最近对:return d>closePoint3(a,n-1)?closePoint3(a,n-1):d;
算法实现:
运行结果:
时间复杂度:O(n)
- 最大字段和问题:
蛮力法:
算法描述:
算法:求最大子段maxSum1()
输入:数组a
输出:最大字段和
过程:1.定义maxSum并初始化为0
2.定义循环变量i=0,i从0到a.length-1执行以下:
2.1定义max=0
2.2定义循环变量j,j从i到a.length-1执行以下:
2.2.1.max+=a[j];
if(max>maxSum)
maxSum=max;
算法实现:
运行结果:
时间复杂度:T(n)=n*n=O(n^2)
分治法:
算法描述:
算法:求最大子段maxSum2()
输入:数组a,起始位置low,终止位置high
输出:最大子段的大小。
过程:1.定义中间值mid,定义左半区域最大值left_max,右半区域最大值right_max,定义left_sum储存左半部分的值,right_sum储存右半区域的值
2.如果只有一个数,返回这个数
3.计算左边区域最大值。
4.计算右边区域最大值。
5.计算整个子段的和
6.比较返回最大值
7.递归实现重复以上操作。
算法实现:
运行结果:
时间复杂度:O(n)
动态规划法:
算法描述:
算法:求最大子段maxSum3()
输入:数组a
输出:最大子段以及其大小
过程:1.定义一个长度和a相同的数组b,定义maxsum并赋值为0
2.定义循环变量i,i从1到a.length-1执行以下:
2.1if(b[i - 1] > 0)
b[i] = b[i - 1] + a[i];
else{ //前面的值小于0 直接从当前原数组开始
b[i] = a[i];
3.定义循环变量j,j从0到a.length-1执行以下:
3.1if(b[j]>maxSum){
s=j;
maxSum=b[j];
4.找到最近子段区间,打印子段内容。
算法实现:
运行结果
时间复杂度:T(n)=n+n=O(n)
总结
1.请从你的实现中选择一题,按照分治(划分-求解-合并)和减治(划分-求解-映射)的特征来进行说明。
最近对问题:
分治法:每次都划分成两部分,从前半区,后半区,中间找最近对,最后比较所有的答案得到最近对的解。
减治法:减一治,每次问题划分成第n对和前n-1对的问题,求解出最近对,最后比较得出最小值即为解。
2.你觉得分治、减治有相同点吗?有不同点吗?请举例说明。
相同点:都将问题分成子问题求解。
不同点:分治法的分二治和减治法的减半治都是讲问题分成规模差不多大小的子问题,但是分治法要对两个子问题都进行求解,减治法则只需对其中一个问题经行求解。