算法第二章上机实践报告
1.实践题目名称
7-1 最大子列和问题
2.问题描述
给定K个整数组成的序列{ N1, N2, ..., NK },“连续子列”被定义为{ Ni, Ni+1, ..., Nj },其中 1≤i≤j≤K。“最大子列和”则被定义为所有连续子列元素的和中最大者。例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。
3.算法描述
用分治法解决。首先,分解成两个子问题:把一个序列分解成两个序列来解决,分别是左序列,右序列。其次,求解“左序列最大连续子段和” 与求解“右序列最大连续子段和”可以用递归函数来实现求解,跨越两段序列的连续子段和由左右两段最大连续子段和相加即可得到。最后比较三个子段和的大小,最大的即是答案。
具体代码如下:
1 #include<iostream>
2 using namespace std;
3
4 int MaxSum(int a[],int left,int right)
5 {
6 int maxsum = 0;
7
8 //递归的变界条件
9 if(left == right){
10 if(a[left] > 0){
11 return a[left];
12 }
13 else{
14 return 0; //如果序列中所有整数皆为负数,则输出0
15 }
16 }
17 else{
18 int mid = (left + right) / 2;
19 int leftsum = MaxSum(a, left, mid); //求左序列最大子段和
20 int rightsum = MaxSum(a, mid+1, right); //求右序列最大子段和
21
22 //求中间序列最大子段和
23 int left_border_sum = 0;
24 int s1 = 0; //临时累加器1
25 for(int i = mid; i >= left; i--)
26 {
27 s1 += a[i];
28 if(s1 > left_border_sum)
29 {
30 left_border_sum = s1;
31 }
32 }
33 int right_border_sum = 0;
34 int s2 = 0; //临时累加器2
35 for(int i = mid+1; i <= right; i++)
36 {
37 s2 += a[i];
38 if(s2 > right_border_sum)
39 {
40 right_border_sum = s2;
41 }
42 }
43
44 int midsum = left_border_sum + right_border_sum;
45
46 maxsum = leftsum > rightsum ? leftsum : rightsum;
47 maxsum = midsum > maxsum ? midsum : maxsum;
48
49 return maxsum;
50 }
51
52 }
53
54 int main()
55 {
56 int K,a[200005];
57 cin>>K;
58 for(int i = 0; i < K; i++)
59 {
60 cin>>a[i];
61 }
62
63 cout<<MaxSum(a, 0, K-1);
64 return 0;
65 }
4.算法时间及空间复杂度分析
一、时间复杂度分析:
①分解子问题:将原序列一分为二,时间复杂度为O(1)
②求解子问题:原问题分解为两个相同的子问题,时间复杂度为2T(n/2)
③合并子问题的解:每一次递归调用,时间复杂度为O(n)
T(n) = O(nlogn)
二、空间复杂度分析:
空间复杂度为O(n),用于存储输入数据
5.心得体会(对本次实践收获及疑惑进行总结)
若只有两个数,则left=0,right=1,mid=(left+right)/2=0,此时划分出的左序列就是从0到-1,此时可以看出左序列的划分变界可能会出错,解决此问题可向上取整变成mid=(left+right+1)/2。
通过这道题,我对分治思想有了更深刻的理解。


浙公网安备 33010602011771号