#include <iostream>
#include <vector>
using namespace std;
//s(tart)表示最大子序列的开始位置,e(nd)表示结束位置
//这里如果有多于一个的最大子序列的时候,只记录开始位置最低的那个
int s=0;
int e=0;
//穷举法,复杂度O(n^3)
long maxSubSum1(const vector<int> &a){
long maxSum=0;
for (int i=0; i<a.size();i++)
{
for (int j=i;j<a.size();j++)
{
long thisSum=0;
for (int k=i; k<=j; k++)
{
thisSum+=a[k];
}
if (thisSum>maxSum){
maxSum=thisSum;
s=i;
e=j;
}
}
}
return maxSum;
}
//也是穷举法,不过减去了上面的一些不必要操作O(n^2)
long maxSubSum2(const vector<int> &a){
long maxSum=0;
for (int i=0; i<a.size(); i++)
{
long thisSum=0;
for (int j=i; j<a.size(); j++)
{
thisSum+=a[j];
if (thisSum>maxSum){
maxSum=thisSum;
s=i;
e=j;
}
}
}
return maxSum;
}
long max3(long a, long b, long c){
if(a<b)
a=b;
if(a>c)
return a;
else
return c;
}
long maxSumRec(const vector<int> a, int left, int right){
if(left == right)
{
//其实这个基准值在后面计算的时候可以保证
//在这里不必多此一举
if(a[left]>0)
return a[left];
else
return 0;
}
int center=(left+right)/2;
long maxLeftSum=maxSumRec(a,left,center);
long maxRightSum=maxSumRec(a,center+1,right);
//某段序列中,求含最右侧元素序列和的最大值
long maxLeftBorderSum=0,leftBorderSum=0;
for (int i=center; i>=left; i--)
{
leftBorderSum+=a[i];
if(leftBorderSum>maxLeftBorderSum)
{
maxLeftBorderSum=leftBorderSum;
s=i;
}
}
//某段序列中,求含最左侧元素序列和的最大值
long maxRightBorderSum=0,rightBorderSum=0;
for (int j=center+1; j<=right; j++)
{
rightBorderSum+=a[j];
if(rightBorderSum>maxRightBorderSum)
{
maxRightBorderSum=rightBorderSum;
e=j;
}
}
return max3(maxLeftSum,maxRightSum,
maxLeftBorderSum+maxRightBorderSum);
}
//该方法我们采用“分治策略”(divide-and-conquer),相对复杂的O(NlogN)的解法
//最大子序列可能在三个地方出现,或者在左半部,或者在右半部,
//或者跨越输入数据的中部而占据左右两部分。前两种情况递归求解,
//第三种情况的最大和可以通过求出前半部分最大和(包含前半部分最后一个元素)
//以及后半部分最大和(包含后半部分的第一个元素)相加而得到。
long maxSubSum3(const vector<int> &a){
return maxSumRec(a,0,a.size()-1);
}
//如果a[i]是负数那么它不可能代表最有序列的起点,因为任何包含a[i]的作为起点的子
//序列都可以通过用a[i+1]作为起点来改进。类似的有,任何的负的子序列不可能是最优
//子序列的前缀。例如说,循环中我们检测到从a[i]到a[j]的子序列是负数,那么我们就可以推进i。
//关键的结论是我们不仅可以把i推进到i+1,而且我们实际可以把它一直推进到j+1。
long maxSubSum4(const vector<int> &a){
long maxSum=0;
long thisSum=0;
int t=0;
for (int j=0; j<a.size(); j++)
{
thisSum+=a[j];
if(thisSum>maxSum){
maxSum=thisSum;
s=t;
e=j;
}
else if(thisSum<0){
thisSum=0;
t=j+1;
}
}
return maxSum;
}
测试程序:
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <ctime>
#include <cstdlib>
using namespace std;
const long COUNT = 1000;
const int MAX_NUM = 200;
int Start = 0;
int End = 0;
bool readFile(vector<int>&input, string fileName)
{
ifstream infile(fileName.c_str());
if(!infile)
{
return false;
}
int s;
while(infile >> s)
{
input.push_back(s);
}
return true;
}
bool writeTestData(string fileName)
{
ofstream outfile(fileName.c_str());
if(!outfile)
{
return false;
}
srand((unsigned)time(NULL));
for(int i = 0; i < COUNT; i++)
{
if(rand() % 2 == 0)
{
outfile << rand() % MAX_NUM << endl;
}
else
{
outfile << ~(rand() % MAX_NUM) <<endl;
}
}
return true;
}
long maxSubSum1(const vector<int>& a)
{
long maxSum = 0;
for(int i = 0; i < a.size(); i++)
{
for(int j = i; j < a.size();j++)
{
long thisSum = 0;
for(int k = i; k <= j; k++)
{
thisSum += a[k];
}
if(thisSum > maxSum)
{
maxSum = thisSum;
Start = i + 1;
End = j + 1;
}
}
}
return maxSum;
}
long maxSubSum2(const vector<int>& a)
{
long maxSum = 0;
for(int i = 0; i < a.size(); i++)
{
long thisSum = 0;
for(int j = i; j <a.size(); j++)
{
thisSum += a[j];
if(thisSum > maxSum)
{
maxSum = thisSum;
Start = i + 1;
End = j + 1;
}
}
}
return maxSum;
}
long max3(long a, long b, long c)
{
if(a < b)
{
a = b;
}
if(a > c)
{
return a;
}
else
{
return c;
}
}
long maxSumRec(const vector<int>&a, int left, int right)
{
if(left == right)
{
if(a[left] > 0)
{
return a[left];
}
else return 0;
}
int center = (left + right) / 2;
long maxLeftSum = maxSumRec(a, left, center);
long maxRightSum = maxSumRec(a, center + 1, right);
long maxLeftBorderSum = 0, leftBorderSum = 0;
for (int i = center; i >= left; i--)
{
leftBorderSum += a[i];
if (leftBorderSum > maxLeftBorderSum)
{
maxLeftBorderSum = leftBorderSum;
Start = i + 1;
}
}
long maxRightBorderSum = 0, rightBorderSum = 0;
for(int j = center + 1; j <= right; j++)
{
rightBorderSum += a[j];
if(rightBorderSum > maxRightBorderSum)
{
maxRightBorderSum = rightBorderSum;
End = j + 1;
}
}
return max3(maxLeftSum, maxRightSum, maxLeftBorderSum + maxRightBorderSum);
}
long maxSubSum3(const vector<int>&a)
{
return maxSumRec(a, 0, a.size() - 1);
}
long maxSubSum4(const vector<int>& a)
{
long maxSum = 0, thisSum = 0;
for (int j = 0; j < a.size(); j++)
{
thisSum += a[j];
if (thisSum > maxSum)
maxSum = thisSum;
else if (thisSum < 0)
thisSum = 0;
}
return maxSum;
}
int main()
{
clock_t start,finish;
vector<int>num;
if(!writeTestData("in.txt"))
{
cout << "写入文件错误" << endl;
}
if(readFile(num, "in.txt"))
{
start = clock();
cout << maxSubSum1(num) << endl;
finish = clock();
//cout << "Start position = " << Start << "\t" << "Start position = " << End <<endl;
printf("Time used = %.2lf\n",(double)(finish - start)/CLOCKS_PER_SEC);
start = clock();
cout << maxSubSum2(num) << endl;
finish = clock();
//cout << "Start position = " << Start << "\t" << "Start position = " << End <<endl;
printf("Time used = %.2lf\n",(double)(finish - start)/CLOCKS_PER_SEC);
start = clock();
cout << maxSubSum3(num) << endl;
finish = clock();
printf("Time used = %.2lf\n",(double)(finish - start)/CLOCKS_PER_SEC);
start = clock();
cout << maxSubSum4(num) << endl;
finish = clock();
printf("Time used = %.2lf\n",(double)(finish - start)/CLOCKS_PER_SEC);
}
return 0;
}
count = 1000
4135
Time used = 12.87
4135
Time used = 0.06
4135
Time used = 0.00
4135
Time used = 0.00
请按任意键继续. . .
count = 2000
8968
Time used = 104.37
8968
Time used = 0.23
8968
Time used = 0.00
8968
Time used = 0.00
请按任意键继续. . .
count = 10000 //O(N^3)略去
15302
Time used = 5.88
15302
Time used = 0.02
15302
Time used = 0.00
请按任意键继续. . .
count = 100000
33853
Time used = 570.03
33853
Time used = 0.16
33853
Time used = 0.01
请按任意键继续. . .
!!!