求最大子序列及其效率解析

来源:互联网 发布:博洋挂机软件 编辑:程序博客网 时间:2024/06/05 13:28
#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;elsereturn c;}long maxSumRec(const vector<int> a, int left, int right){if(left == right){//其实这个基准值在后面计算的时候可以保证//在这里不必多此一举if(a[left]>0)return a[left];elsereturn 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
请按任意键继续. . .

!!!

原创粉丝点击