hdu1081 最大连续子序列和最大连续子矩阵的关系与实现
最大连续子序列和最大连续子矩阵的关系与实现
求最长连续子序列的优化方法(非DP)
//求最大连续子序列和与对应的开头元素和结束元素
实现代码:
#include<stdio.h> #include<string.h> #include<algorithm> #define MAXN 100002 using namespace std; int main() { int i,j,n,a[MAXN],Max,sum,max; int ps,pe,ts,te;//记录开头元素和结束元素 scanf("%d",&n); for(i=0;i<n;i++) scanf("%d",&a[i]); sum=0; Max=INT_MIN; for(i=0;i<n;i++) { if(sum<=0)//如果序列和为负数,初始化sum与开始结束下标 { sum=a[i]; ts=i; te=i; } else//如果序列和为正数,继续累加,并记录新的结尾坐标 { sum+=a[i]; te=i; } if(sum>Max)//一旦发现更大的连续子序列,就更新最大值和开始结束下标 { Max=sum; ps=ts; pe=te; } } printf("%d %d %d\n",Max,a[ps],a[pe]); return 0; }
例子:
8
1 -3 -5 2 6 -1 4 9
20 2 9
类似的是,在矩阵中求最大子矩阵的方法可以转化成一维求最大连续子序列和的方法。
将矩阵的行或列压缩。这里我选择列压缩
如:
1 -1 2
4 9 15
-7 1 10
计算每一递进行的最长连续子序列和,什么是递进行?举个例子
全局变量MAX=-999999999
刚刚的矩阵
1 -1 2
4 9 15
-7 1 10
第一次记算取 1 -1 2
求出最长连续子序列是2,MAX=2
————————————————————————————————————
第二次取
1 -1 2
4 9 15
这里两行的每一列元素之和:5 8 17(从这里开始就体现矩阵压缩了)
求出最长连续子序列是30,MAX=30
————————————————————————————————————
第三次取
1 -1 2
4 9 15
-7 1 10
这里三行的每一列元素之和:-2 9 27
求出最长连续子序列是36,MAX=36
————————————————————————————————————
第四次取:4 9 15
求出最长连续子序列是28,MAX=36
————————————————————————————————————
第五次取
4 9 15
-7 1 10
这里两行的每一列元素之和:-3 10 25
求出最长连续子序列是35,MAX=36
————————————————————————————————————
第六次次取:-7 1 10
求出最长连续子序列是11,MAX=36
————————————————————————————————————
到此为止,所有可能的子矩阵和全都计算完毕,得出最大的子矩阵元素之和为36
即是
-1 2
9 15
1 10
这个子矩阵
#include <bits/stdc++.h> int n; int ma[130][130],pre[130]; using namespace std; int getsum(){ int sum=0,maxn=0; for(int i=0;i<n;i++){ sum+=pre[i]; if(sum>maxn) maxn=sum; if(sum<0 ) sum=0; } return maxn; } void init(){ memset(pre,0,sizeof(pre)); memset(ma,0,sizeof(ma) ); } int main(){ while(~scanf("%d",&n)){ init(); for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ scanf("%d",&ma[i][j]); } } int ans=-999999; for(int i=0;i<n;i++){ //矩阵压缩 memset(pre,0,sizeof(pre)); for(int j=i;j<n;j++){ for(int k=0;k<n;k++){ pre[k]+=ma[j][k]; } int summ=getsum(); if( ans<summ) ans=summ; } } printf("%d\n",ans); } return 0; }