今天算法课讲得是分治算法,以最大子段和为 给定由n个整数(可能为负数)组成的序列:a1,a2,…,an,求该序列的最大子段和。
我最开始想到的是联机算法,从头到尾遍历一次,存放当前最大值和总和,总和小于0舍弃。
分治算法是,分成两个段,递归的去解每个段的结果,每个字问题有三种情况,答案在左段,答案在右段,和包括中点,计算三者答案,找max。第三种情况,从中间往两侧走,和比最大之大保留,反之为0.
// 最大子段和问题.cpp : 定义控制台应用程序的入口点。
//
/*
分成两段 作何有
*/
#include "stdafx.h"
#include <iostream>
#include <vector>
using std::vector;
using std::cout;
using std::endl;
//分而治之算法:把序列分成相同等分 最后答案有三种 只在左边的max 右边的max 左右都包含的max
//然后递归去做左序列和右序列
int divide_and_conquer(vector<int> v,int left,int right) //right是要包括的
{
int sum = 0;
if (left == right)
{
return v[left] > 0 ? v[left] : 0;
}
else
{
int mid = (left + right) / 2;
int leftsum = divide_and_conquer(v, left, mid);//左边最大值
int rightsum = divide_and_conquer(v, mid+1, right);
//包括mid的 从mid往两边走 只要和为正数的 分别设置最大值为s1 s2
int lefts = 0;//总和
int s1 = 0;
for (int i = mid; i >= left; i--)
{
lefts += v[i];
if (lefts > s1)s1 = lefts;
}
int rights = 0;//总和
int s2 = 0;
for (int i = mid+1; i <=right; i++)
{
rights += v[i];
if (rights > s2)s2 = rights;
}
sum = s1 + s2;
if (leftsum > sum)sum = leftsum;
if (rightsum > sum)sum = rightsum;
}
return sum;
}
int fun(vector<int> v) //遍历一次 保存当前最大值和目前的和 如果目前的和小于0 舍弃(联机算法)
//联机算法是在任意时刻算法对要操作的数据只读入(扫描)一次,一旦被读入并处理,它就不需要在被
//记忆了。而在此处理过程中算法能对它已经读入的数据立即给出相应子序列问题的正确答案。
{
int max = 0;
int sum = 0;
for (int i = 0; i < v.size(); i++)
{
sum += v[i];
if (sum < 0)sum = 0;
if (sum > max)max = sum;
}
return max;
}
int main()
{
vector<int> v = {-2,11,-4,13,-5,-2};
vector<int> v2 = {-23,18,20,-7,12,-5,-22};
cout << divide_and_conquer(v2,0,v.size()-1)<< endl;
cout << fun(v2)<<endl;
system("pause");
return 0;
}