最大子段和、最大子矩阵(动态规划)

最大子段和问题:
如果有一个一维数组a[n],如何找出连续的一段,使其元素之和最大呢

1.穷举法
2.动态规划

我们另b[i-1]表示以a[i-1]结尾的最大子段和,那么b[i]只有两种情况b[i-1] + a[i]和a[i],我们取二者最大的,即b[i] = max(b[i -1] + a[i],a[i])(状态转移方程)

代码如下:

int MaxSubArray(int a[],int n)
{
    int i,b = 0,sum = 0;//b记录前一个最大子段和,sum记录最大子段和
    for(i = 0;i < n;i++)
    {
        if(b + a[i] > a[i])                
            b += a[i];  
        else    
            b = a[i];
        if(b > sum)    
            sum = b;
    }
    return sum;
}

最大子矩阵问题

说了这么多,这跟最大子矩阵有什么关系呢?当然有关系学啦!二维就是一维的扩展,把二维压扁不就变成一维了吗?

我们假设所求N*N的矩阵的最大子矩阵是从i列到j列,q行到p行,如下图所示(假设下标从1开始)

a[1][1]  a[1][2]  ······  a[1][i]  ······  a[1][j]   ······  a[1][n]

a[2][1]  a[2][2]  ······  a[2][i]  ······  a[2][j]   ······  a[2][n]

······

a[q][1]  a[q][2]  ······  a[q][i]  ······  a[q][j]  ······  a[q][n]

······

a[p][1]  a[p][2]  ······  a[p][i]  ······  a[p][j]  ······  a[p][n]

······

a[n][1]  a[n][2]  ······  a[n][i]  ······  a[n][j]  ······  a[n][n]

最大子矩阵就是图示红色部分,如果把最大子矩阵同列的加起来,我们可以得到一个一维数组{a[q][i]+······+a[p][i] , ······ ,a[q][j]+······+a[p][j]} ,现在我们可以看出,这其实就是一个一维数组的最大子段问题。如果把二维数组看成是纵向的一维数组和横向的一维数组,那问题不就迎刃而解了吗?把二维转换成了我们刚刚解决了的问题。

蓝桥杯的最大子矩阵的题:最大子矩阵
代码如下:

#include 
#include 
using namespace std;

long long MaxSub(long long arr[],int n){
	long long b = 0;
	long long sum = -1000000000; 
	for(int i = 0;i < n;i++){
		if(b + arr[i] < arr[i]){
			b = arr[i];
		}else{
			b = b + arr[i];
		}
		if(sum < b){
			sum = b;
		}
	}
	return sum;
} 

long long rec[510] = {0};
int tab[510][510] = {0};

int main(){
	
	int n,m;
	cin>>n>>m;
	for(int i = 0;i < n;i++){
		for(int j = 0;j < m;j++){
			int t;
			cin>>t;
			tab[i][j] = t;
		}
	}
	long long maxx = -100000000;
	for(int i = 0; i < n;i++){
		memset(rec,0,sizeof(rec));
		for(int j = i; j < n;j++){
			for(int k = 0;k < m;k++){
				rec[k] += tab[j][k];
			}
			long long t = MaxSub(rec,m);
			if(t > maxx){
				maxx = t;
			}
		}
	}
	cout<

你可能感兴趣的:(动态规划)