Dividir para conquistar: o maior problema de subarray

Dividir para conquistar: o maior problema de subarray

Pergunta:
Dada uma matriz, encontre uma submatriz (contígua) de forma que a soma dos elementos da submatriz seja a maior.
Entrada:
dada uma matriz X [1 ... n], para qualquer par de submatrizes não vazias com subscritos de matriz l, r (l≤r), a soma é registrada como S (l, s).
Saída:
Encontre S O valor máximo de (l, s) é registrado como S max .

analise de problemas

Insira a descrição da imagem aqui

  1. Divida a matriz X [1 ... n] em X [1 ... n / 2] e X [n / 2 + 1 ... n]
  2. Resolva recursivamente o subproblema
    S1 : a maior submatriz da matriz X [1 ... n / 2]
    S2 : a maior submatriz da matriz X [n / 2 + 1 ... n]
  3. Combine os subproblemas para obter S max
    S3 : a maior submatriz do ponto médio. A
    soma das submatrizes mais principescas da matriz X S max = max {S1, sz, s3}

O valor de gargalo da eficiência de execução está no aspecto da fusão, que é o problema de resolver S3.

Solução S3:
Insira a descrição da imagem aqui

  1. 记 mid = n / 2

  2. S3 pode ser dividido em duas partes
    Esquerda : a soma da maior submatriz terminando com X [mid]
    Direita : a soma da maior submatriz começando com X [mid + 1]
    S3 = Esquerda + Direita

    Solução da esquerda:
    percorra a soma de X [meio] para a frente e registre o valor máximo
    Insira a descrição da imagem aqui
    . Solução da direita:
    percorra a soma de X [meio +1] para trás e registre o valor máximo
    Insira a descrição da imagem aqui

Complexidade de tempo S3:

  1. Complexidade do tempo restante: O (meio)
  2. Complexidade de tempo certo: O (n-mid)
  3. Complexidade de tempo S3: O (n)

Diagrama de análise de algoritmo

Insira a descrição da imagem aqui

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;
}

Acho que você gosta

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