zoukankan      html  css  js  c++  java
  • 求最大子序列及其效率解析

    #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
    请按任意键继续. . .

    !!!

  • 相关阅读:
    【BZOJ2067】[Poi2004]SZN
    BZOJ4675
    [bzoj3522][bzoj4543][POI2014]HOTEL
    bzoj2969矩形粉刷
    bzoj2969矩形粉刷
    1419: Red is good
    【BZOJ2698】染色
    BZOJ5084[hashit]
    [WC2014]紫荆花之恋
    齐次常系数递推关系式
  • 原文地址:https://www.cnblogs.com/lgh1992314/p/5835270.html
Copyright © 2011-2022 走看看