1. 程式人生 > 其它 >3.給定一個整數序列,求其中整數加起來最大子序列和(因為該數列中可能有負數)-窮舉法,分治法

3.給定一個整數序列,求其中整數加起來最大子序列和(因為該數列中可能有負數)-窮舉法,分治法

3.給定一個整數序列,求其中整數加起來最大子序列和(因為該數列中可能有負數)-分治法

參考文獻:程式設計珠璣第八章-分治演算法

分治演算法求解:

#include <stdio.h>
#define max(a,b) a>b?a:b

//---------------------------------
//
// 需求:
// 給定一個整數序列,求其中整數加起來最大子序列和(因為該數列中可能有負數)
// 
//--------------------------------


//---------------------
//法1:直接翻譯的解法(窮舉法)
// 時間複雜度:O(n^3)
//-----------------------
int MaxSubseqSum1(int A[], int N) {
	int ThisSum, MaxSum = 0;
	int i, j;
	for (i = 0; i < N; i++) {//i是子列的左端位置
		for (j = i; j < N; j++) {//j是子列的右端位置
			ThisSum = 0;
			for (int z = i; z <= j; z++) {
				ThisSum += A[z];
				if (ThisSum > MaxSum) {
					MaxSum = ThisSum;
				}
			}
			
		}

	}
	return MaxSum;
}

//---------------
//法1的優化版:(窮舉法優化)
// 畫一個圖即可理解,當i為定值時,只要累加j下標所對應的值,就可以找到從i起所對應的最大序列和,如此迴圈則可以找到所有遍歷的最大序列和
// 時間複雜度:O(n^2)
//---------------
int MaxSubseqSum2(int A[], int N) {
	int ThisSum, MaxSum = 0;
	int i, j;
	for (i = 0; i < N; i++) {//i是子列的左端位置
		ThisSum = 0;
		for (j = i; j < N; j++) {//j是子列的右端位置
			ThisSum += A[j];
			if (ThisSum > MaxSum) {
				MaxSum = ThisSum;
			}
		}

	}
	return MaxSum;
}

//-----------------
//法3:分治思想
// 4,-3,5,-2,-1,2,6,-2
// 
// 設計:不會(參考程式設計珠璣)
// 
//------------------

//用於比較3個數值大小
float max1(float a, float b, float c) {
	if (a > b && a > c) {
		return a;
	}
	else if (b > a && b > c) {
		return b;
	}
	else {
		return c;
	}
}

float arr[] = { 4,-3,5,-2,-1,2,6,-2 };
float maxsum3(int L, int R) {

	if (L > R) {//表示陣列中沒有元素
		return 0;
	}
	if (L == R) {//只有一個元素返回該元素相對於0的最大值
		return max(0, arr[L]);
	}
	int m = (L + R) / 2;//中位數的下標

	/*
	以下兩個for迴圈的目的:找出跨越對應的最大子序列和
	*/
	float Lmax = 0, sum = 0;
	for (int i = m; i >= L; i--) {
		sum += arr[i];
		Lmax = max(Lmax, sum);
	}

	float Rmax = 0;
		sum = 0;
	for (int i = m+1; i <= R; i++) {
		sum += arr[i];
		Rmax = max(Rmax, sum);
	}
	return max1(Lmax + Rmax, maxsum3(L, m), maxsum3(m+1, R));

}


int main(void) {
	
	float sumMax = maxsum3(0, 7);
	printf("%f\n", sumMax);
}


執行結果: