1.子序列最大和问题:
给你一串序列x1,x2,……,xn,求max(i,j){xi+……+xj}。
枚举i,j时间复杂度O(N*N)。
简单dp:
设d[i]表示以i结尾的最大序列和。
则ans=max(d[i])。
d[i] = max(d[i-1]+x[i],x[i]);
O(N*N) -> O(N) .
2.最大子矩阵和问题:
给定二维矩阵m[i][j],求某子矩阵的最大和.
ans = max(sum(x1,y1,x2,y2))。
sum(x1,y1,x2,y2)表示行为x1->x2,列为y1->y2的子矩阵的和。
显然枚举x1,y1,x2,y2复杂度为O(n^4)。
解法:套用一维最大序列和。
枚举x1,x2,可用O(N)的方法得到当最优解行为x1,x2的最大值。
这里只用把x[i]换成sum[x2]-sum[x1]即可。。
参考poj1050.
以上多维子矩阵问题可以类似推广,不过仅仅将算法复杂度降低一个数量级。
3.求某个子矩阵,其和最接近某个值T,最接近指|x-T|的值最小。
参考oj网址:http://cstest.scu.edu.cn/soj/problem.action?id=2691
(华迪实训,完善一下)
O(N)求一维情况,假定x[i]均为非负数。
则记d[i]表示以i结尾的不超过T的最大值,l[i]记录其左边界。
t = d[i-1] + x[i] ;
比较t和ans看谁更加接近T。
更新d[i],d[i] = t , l[i] = l[i-1] ;
若t > T ,则 while(d[i]-m[l[i]]>T) l[i]++;
附代码如下:
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #include <algorithm>
- #include <map>
- #include <set>
- using namespace std;
- inline bool get(int &t)
- {
- bool flag = 0 ;
- char c;
- while(!isdigit(c = getchar())&&c!='-') if( c == -1 ) break ;
- if( c == -1 ) return 0 ;
- if(c=='-') flag = 1 , t = 0 ;
- else t = c ^ 48;
- while(isdigit(c = getchar())) t = (t << 1) + (t << 3) + (c ^ 48) ;
- if(flag) t = -t ;
- return 1 ;
- }
- const int maxn = 21 ;
- int n , m , d[maxn][maxn*100] , s[maxn][maxn*100] ;
- inline int get_max(int a,int b) { return a > b ? a : b ; }
- inline int get_min(int a,int b) { return a < b ? a : b ; }
- inline int get_abs(int a) { return a < 0 ? -a : a ; }
- int main()
- {
- int sth , i , j , k , t , l , r , key , sum ;
- set<int> mp;
- set<int>::iterator ite ;
- /*for( i = 1 ; i < 10 ; i += 2 )
- mp.insert(i);
- while (get(j))
- {
- printf("%d,%d\n",*lower_bound(mp.begin(),mp.end(),j),*upper_bound(mp.begin(),mp.end(),j));
- }*/
- for( sth = 1 ; get(n) ; sth++)
- {
- get(m); get(key);
- memset(s,0,sizeof(s));
- memset(d,0,sizeof(d));
- for ( i = 1 ; i <= n ; i++)
- {
- for( j = 1 ; j <= m ; j++)
- {
- get(k);
- s[i][j] = s[i-1][j] + k ;
- }
- }
- int ans = 0x7fffffff ;
- for ( i = 0 ; i < n ; i++)
- {
- for ( k = i+1 ; k <= n ; k++)
- {
- //[i][k]区间
- mp.clear();
- t = s[k][1]-s[i][1] ;
- mp.insert(t); mp.insert(0);
- if( get_abs(ans-key) > get_abs(t-key) ) ans = t ;
- for ( j = 2 ; j <= m ; j++)
- {
- t += s[k][j]-s[i][j] ;
- ite = mp.lower_bound(t-key);
- if( ite == mp.end() )
- {
- --ite;
- l = r = *ite;
- }
- else
- {
- r = *ite ;
- if( ite == mp.begin() )
- l = 0 ;
- else ite--;
- l = *ite ;
- }
- mp.insert(t);
- if( get_abs(ans-key) > get_abs(t-l-key) ) ans = t - l ;
- if( get_abs(ans-key) > get_abs(t-r-key) ) ans = t - r ;
- }
- }
- }
- printf("Case %d:\n%d\n",sth,ans);
- }
- }
- /*
- 22
- 1 9
- 2 1
- */