1. 程式人生 > >最大連續和

最大連續和

完全 std CI return left 起點 int OS n+1

問題:給出一個長度為n的序列a1,a2,a3....an,求最大連續和,即找到1<=i<=j<=n,是的ai+...+aj最大

1.暴力枚舉

int sum = 0;
int max = 0;
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
sum = 0;
for (int k = i; k <= j; k++)
sum += a[k];
if (max < sum)
max = sum;
}
}

T(n)=n(n+1)(n+2)/6=O(n3)

2.遞推

利用前綴

int s[100];
int max = 0;
s[0] = a[0];
for (int i = 1; i < n; i++)
s[i] = s[i - 1] + a[i];
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
int t = i == 0 ? s[j] : s[j] - s[i - 1];
max = Max(max, t);
}
}

T(n)=O(n2)

3.分治法

1)劃分:把序列分成元素個數盡量相等的兩半;

2) 遞歸求解:分別求出完全位於左半或者完全位於右半的最佳序列

3)合並:求出起點位於左半,終點位於右半的最大連續和序列,並和子問題的最優解比較

關鍵在於“合並”步驟,既然起點位於左半,終點位於右半,我們可以認為地把這樣的序列分成兩部分,

然後獨立求解:先尋找最佳起點,然後再尋找最佳終點。

int maxsum3(int a[], int left, int right) { //左閉右開
int i, m, v, L, R, max;
if (right - left == 1) return a[left];
m = left + (right - left) / 2; //第一步,劃分成[left,m),[m,right)
max = Max(maxsum3(a, left, m), maxsum3(a, m, right));
//第二步,遞歸求解

//第三步,合並
v = 0; L = a[m - 1];
for (i = m - 1; i >= left; i--)
L = Max(L, v += a[i]);
v = 0; R = a[m];
for (i = m; i < right; i++)
R = Max(R, v += a[i]);
return Max(max, L + R);
}

// 練習.cpp: 定義控制臺應用程序的入口點。
//

#include "stdafx.h"

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>
#include<windows.h>

using namespace std;

int Max(int a, int b) {
	return a > b ? a : b;
}

//暴力枚舉

int maxsum1(int a[], int n) {
	int sum = 0;
	int max = 0;
	for (int i = 0; i < n; i++) {
		for (int j = i; j < n; j++) {
			sum = 0;
			for (int k = i; k <= j; k++)
				sum += a[k];
			if (max < sum)
				max = sum;
		}
	}
	return max;
}

//遞推前綴

int maxsum2(int a[], int n)
{
	int s[100];
	int max = 0;
	s[0] = a[0];
	for (int i = 1; i < n; i++)
		s[i] = s[i - 1] + a[i];
	for (int i = 0; i < n; i++) {
		for (int j = i; j < n; j++) {
			int t = i == 0 ? s[j] : s[j] - s[i - 1];
			max = Max(max, t);
		}
	}
	return max;
}

//分治法
      
int maxsum3(int a[], int left, int right) {    //左閉右開
	int i, m, v, L, R, max;
	if (right - left == 1) return a[left];
	m = left + (right - left) / 2;             //第一步,劃分成[left,m),[m,right)
	max = Max(maxsum3(a, left, m), maxsum3(a, m, right));
	                                           //第二步,遞歸求解
	v = 0; L = a[m - 1];                       //第三步,合並
	for (i = m - 1; i >= left; i--)
		L = Max(L, v += a[i]);
	v = 0; R = a[m];
	for (i = m; i < right; i++)
		R = Max(R, v += a[i]);
	return Max(max, L + R);
}

int main()
{
	int n;
	int a[100];
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> a[i];
	}
	int s1 = maxsum1(a, n);
	int s2 = maxsum2(a, n);
	int s3 = maxsum3(a, 0, n);
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	system("pause");
	return 0;
}

最大連續和