首页 > 代码库 > 动态规划-最大子矩阵

动态规划-最大子矩阵

问题:给一列数n个,求最大连续子序列和(即连续的子序列中和最大的序列)若所有K个元素都是负数,则定义其最大和为0,输出整个序列的首尾元素  本文作者 凌风 csdn (iaccepted)

拓展:给一个n*n的矩阵,求其中和最大的子矩阵(即所有子矩阵中和最大的阵)

首先也是从最简单的着手,拿到问题,很容易想到的就是直接爆搜(求所有可能的子序列和并找出最大的即可)时间复杂度为n^2

[cpp] view plain copy
 print?技术分享技术分享
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <limits.h>  
  4.   
  5.   
  6. #define N 10002  
  7. /* 
  8. problem:求最大连续子序列的问题dp 
  9. time:n^2 
  10. */  
  11.   
  12. int main(){  
  13.     int a[N],i,j,maxx,sum,n,ps,pe;  
  14.   
  15.   
  16.     scanf("%d",&n);  
  17.     for(i=0;i<n;++i){  
  18.         scanf("%d",&a[i]);  
  19.     }  
  20.   
  21.   
  22.     maxx = INT_MIN;//初始为最小整数  
  23.     for(i=0;i<n;++i){  
  24.         sum = 0;  
  25.         for(j=i;j<n;++j){//i,j两个子循环来遍历所有的子序列并计算其和(a[i]加到a[j])  
  26.             sum += a[j];  
  27.             if(sum>maxx){//把和大的保留并记录下最大序列的始末位置ps、pe  
  28.                 maxx = sum;  
  29.                 ps = i;  
  30.                 pe = j;  
  31.             }  
  32.         }  
  33.     }  
  34.     printf("%d %d %d\n",maxx,a[ps],a[pe]);  
  35. }  


上面的这段代码思路非常的清晰也便于理解,但是数据量大的话时间消耗也会很大,当然ACM的要求肯定是达不到了,现在做时间复杂度为n的算法来解决该问题。

该算法基于的思想也很简单,最大连续子序列和的第一个元素不可能是负数,这点很好证明(反证),假设a[i…j]为最大的连续子序列且a[i]为负,那我a[i+1…j]的和将会大于a[i…j]的和,所以与原假设矛盾,这就能推出最大子序列和的第一个元素不可能是负数。得到这个结论我们就可以进一步进行推广,那就是如果一个子序列的和为负数,那么这个序列不可能是最大连续子序列中的开始的一段序列(类似于第一个元素的方法可得到证明即把这段和看做是一个元素)。根据这一思想就可以得到本体线性的算法。

[cpp] view plain copy
 print?技术分享技术分享
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <limits.h>  
  4.   
  5.   
  6. #define N 10002  
  7.   
  8. int main(){  
  9.     int a[N],maxx,i,n,sum,ps,pe,ts,te;  
  10.   
  11.   
  12.     scanf("%d",&n);  
  13.     for(i=0;i<n;++i){  
  14.         scanf("%d",&a[i]);  
  15.     }  
  16.   
  17.   
  18.     sum = 0;  
  19.     maxx = INT_MIN;  
  20.   
  21.   
  22.     for(i=0;i<n;++i){  
  23.         if(sum<=0){//如果前面的和为负,则前面的序列舍掉从本元素开始重新确定新序列  
  24.             sum = a[i];  
  25.             ts = i;  
  26.             te = i;  
  27.         }else{//如果前面的和为正,则可能出现在最大序列中,所以要继续累加  
  28.             sum += a[i];  
  29.             te = i;  
  30.         }  
  31.   
  32.   
  33.         if(sum>maxx){//记录下最大子序列和及起始和结束位置  
  34.             maxx = sum;  
  35.             ps = ts;  
  36.             pe = te;  
  37.         }  
  38.     }  
  39.   
  40.   
  41.     printf("%d %d %d\n",maxx,a[ps],a[pe]);  
  42.     return 0;  
  43. }  

至此,最大连续子序列问题得到解决。

下面记录下最大子矩阵和的求法。

其实最大子矩阵和的算法就是最大连续子序列的一个拓展问题,思路很简单,就是将矩阵先预处理下,按列累加,然后通过三个循环变量来遍历所有的子矩阵,对每个子矩阵以列和为元素转化为n个元素序列求最大连续子序列的问题就可以了。

 

 

本文作者 凌风 csdn(iaccepted)

作者博客:http://blog.csdn.Net/iaccepted,欢迎交流

动态规划-最大子矩阵