子数组之和的最大值(二维)

《编程之美》 2.15 子数组之和的最大值(二维)

解法一:遍历,穷举。

代码一:

int Sum(int **A, int a, int b, int c, int d)
{
	int sum = 0;
	int i,j,k,l;
	for(i = a; i <= c; i++){
		for (j = b; j <= d; j++){
			sum += A[i][j]; 
		}
	}
	return sum;
}

int MaxSum(int **A,int M,int N)
{
	int iMin,iMax,jMin,jMax;
	int sum = -INT_MAX;
	int tmp;
	for(iMin = 0; iMin < M; iMin++){
		for(jMin = 0; jMin < N; jMin++){
			for(iMax = iMin; iMax < M; iMax++){
				for(jMax = jMin; jMax < N; jMax++){
					tmp = Sum(A,iMin,jMin,iMax,jMax);
					sum = tmp > sum ? tmp : sum;
				}
			}
		}
	} 
	return sum;
}

解法二:利用一维数组的DP算法,将二维看成一维来求解。

代码二:

int MaxSum2(int **A,int M,int N)
{
	int maxsum = -INT_MAX;
	int nStart;
	int nAll ;
	int tmp;
	int **ps = (int **)malloc((M+1)*sizeof(int*));
	for(int i = 0; i <= M; i++){
		ps[i] = (int *)malloc((N+1)*sizeof(int));
	}
	for (int i = 0; i <= M; i++)
		ps[i][0] = 0;
	for (int j = 0; j <= N; j++)
		ps[0][j] = 0;
	for(int i = 1; i <= M; i++){
		for(int j = 1; j <= N; j++){
			ps[i][j] = ps[i-1][j] + ps[i][j-1] - ps[i-1][j-1] + A[i-1][j-1];
		}
	}
	for(int a = 0; a < M; a++){
		for(int c = a; c < M; c++){
			nStart = ps[c+1][N] - ps[a][N] - ps[c+1][N-1] + ps[a][N-1];
			nAll = ps[c+1][N] - ps[a][N] - ps[c+1][N-1] + ps[a][N-1];
			for (int i = N-1; i > 0; i--){
				tmp = ps[c+1][i] - ps[a][i] - ps[c+1][i-1] + ps[a][i-1];
				nStart = tmp + nStart > tmp ? tmp + nStart : tmp;
				nAll = nStart > nAll ? nStart : nAll; 
			}
			maxsum = maxsum < nAll ? nAll : maxsum; 
		}
	}
	
	for(int i = 0; i <= M; i++){
		free(ps[i]);
	}
	free(ps);
	
	return maxsum; 
}

测试程序:

#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <time.h>

void show(int **A,int M,int N);
int Sum(int **A, int a, int b, int c, int d)
{
	int sum = 0;
	int i,j,k,l;
	for(i = a; i <= c; i++){
		for (j = b; j <= d; j++){
			sum += A[i][j]; 
		}
	}
	return sum;
}

int MaxSum(int **A,int M,int N)
{
	int iMin,iMax,jMin,jMax;
	int sum = -INT_MAX;
	int tmp;
	for(iMin = 0; iMin < M; iMin++){
		for(jMin = 0; jMin < N; jMin++){
			for(iMax = iMin; iMax < M; iMax++){
				for(jMax = jMin; jMax < N; jMax++){
					tmp = Sum(A,iMin,jMin,iMax,jMax);
					sum = tmp > sum ? tmp : sum;
				}
			}
		}
	} 
	return sum;
}
/*----------------------------------------------------------------------------------------*/
int MaxSum2(int **A,int M,int N)
{
	int maxsum = -INT_MAX;
	int nStart;
	int nAll ;
	int tmp;
	int **ps = (int **)malloc((M+1)*sizeof(int*));
	for(int i = 0; i <= M; i++){
		ps[i] = (int *)malloc((N+1)*sizeof(int));
	}
	for (int i = 0; i <= M; i++)
		ps[i][0] = 0;
	for (int j = 0; j <= N; j++)
		ps[0][j] = 0;
	for(int i = 1; i <= M; i++){
		for(int j = 1; j <= N; j++){
			ps[i][j] = ps[i-1][j] + ps[i][j-1] - ps[i-1][j-1] + A[i-1][j-1];
		}
	}
	for(int a = 0; a < M; a++){
		for(int c = a; c < M; c++){
			nStart = ps[c+1][N] - ps[a][N] - ps[c+1][N-1] + ps[a][N-1];
			nAll = ps[c+1][N] - ps[a][N] - ps[c+1][N-1] + ps[a][N-1];
			for (int i = N-1; i > 0; i--){
				tmp = ps[c+1][i] - ps[a][i] - ps[c+1][i-1] + ps[a][i-1];
				nStart = tmp + nStart > tmp ? tmp + nStart : tmp;
				nAll = nStart > nAll ? nStart : nAll; 
			}
			maxsum = maxsum < nAll ? nAll : maxsum; 
		}
	}
	
	for(int i = 0; i <= M; i++){
		free(ps[i]);
	}
	free(ps);
	
	return maxsum; 
}
/*-----------------------------------------------------------------------------------------*/
void show(int **A,int M,int N)
{
	for (int i = 0; i < M; i++){
		for(int j = 0; j < N; j++){
			printf("%3d",A[i][j]);
		}
		printf("\n");
	}	
}


int main()
{
	int M = 5;
	int N = 6;
	int **A = (int **)malloc(M*sizeof(int*));
	srand(time(NULL));
	for(int i = 0; i < M; i++){
		A[i] = (int*) malloc(N*sizeof(int));
		for (int j = 0; j < N; j++){
			A[i][j] = ((rand() & 0x1) ? -1 : 1)*(rand() % 9 + 1);			
		}
 	}
	show(A,M,N);
	printf("Max sub sum : %d .\n",MaxSum(A,M,N));
	printf("Max sub sum : %d .\n",MaxSum2(A,M,N));
	
	for(int i = 0; i < M; i++){
		free(A[i]);			
 	}
 	free(A);
} 


测试输出:

  4 -5  4  5  4  6
  9  1 -6 -2  2  5
 -7 -3 -3  8 -8 -1
  1 -6  1  7 -4 -4
  5  9  4  7  4 -4
Max sub sum : 33 .
Max sub sum : 33 .

REF:

1,编程之美 2.15 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值