最大子序列跟最大子矩阵
最大子序列和最大子矩阵
最大子序列:
问题描述:给定整数序列:a1,a2,a3,...an(可能有负数),求a1~an的一个子序列ai~aj,使其和最大
我们很容易想到一个O(n^2)复杂度的方法,即 i : 1--->n,并令 s = 0,然后 j : i---->n, s<---s + a[j],更新maxsum,如若想得到具体的子序列,我们可设i1,j1,更新maxsum时,同时更新下标,不过为了减少运算,我们在更新时做个判断if i1 ≠ i,i1<--i
int sub_sum(int *a,int size,int &i1,int &j1) { int i,j,s,maxsum; maxsum = a[0]; i1 = j1 = 0; for(i=0;i<size;i++) { s = 0; for(j=i;j<size;j++) { s += a[j]; if(s > maxsum) { maxsum = s; if(i1 != i) i1 = i; j1 = j; } } } return maxsum; }
我们注意到,每次在对s求和时,可能遇到部分和小于0,这样的话,显然应该舍弃前面的部分和序列,这实际上有动态规划的思想,复杂度为O(n),具体方法如下:
初设maxsum <--a[0],s=i1 = j1 = temp_i<--0,在扫描数组中,我们记下当前子序列和s,然后试图更新maxsum,j1(<---i),i1(<--temp_i,i1≠temp_i1)再判断s是否小于0,小于则置s = 0,同时更新temp_i为i+1,
#include <stdio.h> int sub_sum(int *a,int size,int &i1,int &j1) { int i,maxsum,s,temp_i; maxsum = a[0]; i1 = j1 = temp_i = 0; s = 0; for(i=0;i<size;i++) { s += a[i]; if(s > maxsum) { maxsum = s; if(temp_i != i1) i1 = temp_i; j1 = i; } if(s < 0)//此处不可用else if,因为有可能s > maxsum且s <0 { s = 0; temp_i = i+1; } } return maxsum; } int main() { int a[8] = {4,-3,-4,8,-5,7,-5,7}; int i,i1,j1; printf("%d-->%d:%d\n",i1,j1,sub_sum(a,8,i1,j1)); return 0; }
最大子矩阵:
问题描述:给定一个n*m的矩阵A,求A中的一个非空子矩阵,使这个子矩阵中的元素和最大。其中,A的子矩阵指在A中行和列均连续的一块。
思路:m<n时,固定第i列到第j列的范围(否则固定第i到j行),寻找在这个范围内的最大子矩阵,即把每行第i列上的元素到第j列的元素分别求和,就转变为了一维的情况。由于有C(m,2)种列的组合,而求一维的子序列需要n的时间,所以,总体上时间复杂度为O(n*m*m)。
#include <stdio.h> #include <stdlib.h> #include <string.h> #define N 501 int a[N][N]; int n,m; int sub_sum(int *b,int *temp,int *temp1) { int s,max,temp2,i; s = max = b[1]; *temp = *temp1 = temp2 = 1; for(i=2;i<=n;i++) { s += b[i]; if(s > max) { max = s; if(*temp != temp2) *temp = temp2; *temp1 = i; } if(s < 0) { s = 0; temp2 = i+1; } } return max; } int main() { int i,j,t,maxsum,s; int maxi,maxj,maxi1,maxj1,temp,temp1; maxi = maxj = maxi1 = maxj1 = temp = temp1 = 1; int *b; scanf("%d%d",&n,&m);//行、列 b = (int *)malloc(sizeof(int)*(n+1)); for(i=1;i<=n;i++) for(j=1;j<=m;j++) { scanf("%d",&a[i][j]); } maxsum = a[1][1]; for(i=1;i<=m;i++) { memset(b,0,(n+1)*sizeof(int)); for(j=i;j<=m;j++) { //固定i,j列 for(t=1;t<=n;t++) b[t] += a[t][j];//自底向上(m,m,n) s = sub_sum(b,&temp,&temp1); if(s > maxsum) { maxsum = s; if(temp != maxi) maxi = temp; if(temp1 != maxi1) maxi1 = temp1; if(i != maxj) maxj = i; if(j != maxj1) maxj1 = j; } } } printf("(%d,%d)--->(%d,%d):%d\n",maxi,maxj,maxi1,maxj1,maxsum);//最大子矩阵的左上角和右下角坐标点及和 return 0; }
参照:http://blog.****.net/luxiaoxun/article/details/7438315