Dividir y conquistar: el mayor problema de subarreglos

Dividir y conquistar: el mayor problema de subarreglos

Pregunta:
Dada una matriz, busque una submatriz (contigua) para que la suma de los elementos de la submatriz sea la más grande.
Entrada:
Dada una matriz X [1 ... n], para cualquier par de submatrices no vacías con subíndices de matriz l, r (l≤r), la suma se registra como S (l, s).
Salida:
Encuentra S El valor máximo de (l, s) se registra como S máx .

análisis del problema

Inserte la descripción de la imagen aquí

  1. Divida la matriz X [1… n] en X [1… n / 2] y X [n / 2 + 1… n]
  2. Resuelva de forma recursiva el sub-problema
    S1 : el sub-arreglo más grande del arreglo X [1… n / 2]
    S2 : el sub-arreglo más grande del arreglo X [n / 2 + 1… n]
  3. Combine los subproblemas para obtener S max
    S3 : el sub-arreglo más grande en el punto medio. La
    suma de los sub-arreglos más principescos del arreglo X S max = max {S1, sz, s3}

El valor del cuello de botella de la eficiencia de ejecución está en términos de fusión, que es el problema de resolver S3.

Solución S3:
Inserte la descripción de la imagen aquí

  1. 记 medio = n / 2

  2. S3 se puede dividir en dos partes
    Izquierda : la suma de la submatriz más grande que termina en X [mid]
    Derecha : la suma de la submatriz más grande que comienza con X [mid + 1]
    S3 = Izquierda + Derecha

    Solución de la izquierda:
    recorra la suma de X [mid] hacia adelante y registre el valor máximo
    Inserte la descripción de la imagen aquí
    . Solución de la derecha:
    recorra la suma de X [mid +1] hacia atrás y registre el valor máximo
    Inserte la descripción de la imagen aquí

Complejidad del tiempo S3:

  1. Complejidad del tiempo izquierdo: O (medio)
  2. Complejidad en el momento adecuado: O (n-mid)
  3. Complejidad de tiempo S3: O (n)

Diagrama de análisis de algoritmos

Inserte la descripción de la imagen aquí

Código

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

const int N = 10000; 
int q[N];    // 序列 

// 求跨越中间的最大子序列 
int findMidSum(int l, int mid, int r) {
    
    
	int leftSum = -100000, rightSum = -100000;   // 初始化为 -100000 是为了防止出现负数和的情况 
	int sum = 0;  // sum 即向左和向右最大的子序列的和 
	for (int i=mid; i>=l; i--) {
    
    
		sum += q[i];
		// 从mid开始向左加不断更新最大值,最后计算出来的即mid左边最大的子序列的值
		leftSum = max(leftSum, sum);    
		// max()函数为 #include<algorithm>中的方法,可以比较两个数的大小,返回较大的数
	}
	sum = 0;
	for (int i=mid+1; i<=r; i++) {
    
    
		sum += q[i];
		// 从mid开始向右加不断更新最大值,最后计算出来的即mid右边最大的子序列的值 
		rightSum = max(rightSum, sum);
	}
	return leftSum + rightSum;
}

// 分治求左右两端最大的子序列和并将其与跨越中间的子序列的和比较大小,返回最大连续子序列的和 
int maxSubArr(int l, int r) {
    
    
	if (l == r) return q[l];    // 递归出口 
	
	int mid = l + r >> 1; //右移一位,相当于除2;也可以写成 mid = l+(r-l)/2;
	int leftSum = maxSubArr(l, mid);
	int rightSum = maxSubArr(mid+1, r);
	int midMaxSum = findMidSum(l, mid, r);
	 
	int res = max(leftSum, rightSum);
	res = max(res, midMaxSum);
	// 返回最大的子序列和 
	return res;
}

int main() {
    
    
	int n;
	cin >> n;
	for (int i=0; i<n; i++) scanf("%d", &q[i]);
	
	int res = -100000;
	res = maxSubArr(0, n-1);
	cout << res;
	return 0;
}

Supongo que te gusta

Origin blog.csdn.net/qq_44524918/article/details/108929861
Recomendado
Clasificación