去年有想过将研究过的动态规划总结一下,不过那时没有写博客习惯,后来就不了了之了。这次不作大而无望的总结了,有一点说一点。
以下部分代码和分析出自《计算机算法设计与分析》(王晓东 编著)。
最大子段和问题复杂度为O(n)的解法,在上篇博客最大连续子序列中已经谈过了。这里在稍微提及一下,主要是更形式化的说明为什么是用动态规划。然后谈一下这个问题的分治解法。
设所要求的序列为 , 记:
也就是说:
那么原问题转化为:
而数组b是可以递归表达的,如下:
或者表示为:
这样就很明显的显示出了最优子结构性质。
具体算法就不给了,上篇博客已经给出了。
分治法的思路是将原数组等分成两个数组,分别在两个数组中求最大子段和。则最终的最大子段和有三种情况:
int MaxSubSum(int *a, int left, int right)
{
int sum = 0;
if(left == right) sum = a[left]>0?a[left]:0;
else
{
int center = (left+right)/2;
int leftsum = MaxSubSum(a, left, center);
int rightsum = MaxSubSum(a, center+1, right);
int s1 = 0;
int lefts = 0;
for(int i = center ; i >= left ; i--)
{
lefts+=a[i];
if(lefts > s1) s1 = lefts;
}
int s2 =0, rights =0;
for(int i = center + 1 ; i <= right; i++)
{
rights += a[i];
if(rights > s2) s2 = rights;
}
sum = s1+s2;
sum = Max(sum, leftsum, rightsum);
}
return sum;
}
最大M子段和是最大子段和问题的推广,给定n个正数(可能为负,因此结果也可能是负的,这点与上篇当结果为负时输出0还是有区别的)组成的序列 , 以及一个正整数m,求该序列中m个不相交的子段,使其总和最大。显然m
int a[MaxN], b[MaxM][MaxN];
int MaxSum(int m, int n )
{
for(int i = 0 ; i <= m ; i++) b[i][0] = 0;
for(int j = 1 ; j <= n ; j++) b[0][j] = 0;
for(int i = 1 ; i <= m ; i++)
{
for(int j = i ; j <= n - m + i ; j++)
{
if(j>i)//取其上一行从i-1到j-1的最大元素与a[j]相加
{
.....//省略
}
else
{
b[i][j] = b[i-1][j-1]+a[j];
}
}
}
int sum = 0;
for(int j = m ; j <= n ; j++)
if(sum < b[m][j]) sum = b[m][j];
return sum;
}
//max m sum
//dynamic programming
//hdj 1024
//625MS 1852K 1052 B
#include
#define MAXN 1000001
using namespace std;
typedef long long ULONG;
ULONG a[MAXN];
ULONG MaxSum(long n, long m)
{
ULONG* b = new ULONG[n-m+2];
long i ;
for( i = 1 ; i <= n-m+1 ; i++) b[i] = 0;
for( i = 1 ; i <= m ; i++ )
{
b[1] = b[1] + a[i];
ULONG max = b[1];
long j;
ULONG bleft = b[1];
for( j = 2 ; j <= n-m+1; j++ )
{
ULONG tmp1 = b[j] + a[i+j-1];//上一排至此为止的最大元素
ULONG tmp2 = bleft + a[i+j-1];//该元素左边的元素
bleft = tmp1>tmp2?tmp1:tmp2;
if( bleft > max ) max = bleft;
b[j] = max;
}
}
ULONG rt = b[n-m+1];
delete [] b;
return rt;
}
int main()
{
long n,m;
while( cin>>m>>n )
{
long i;
for( i = 1 ; i <= n ; i++ ) cin>>a[i];
cout<
除了数组a之外,算法的空间复杂度是 ,时间复杂度 .
//The Max Sub Matrix Sum
//dynamic programming
//hdu 1081
//0MS 336K 1055 B
#include
#include
#define MAXN 101
using namespace std;
int a[MAXN][MAXN];
long MaxSumSubArray(int* aa, int n)
{
long sum = 0, b = 0;
for(int i = 0; i < n ; i++)
{
if(b>0) b+=aa[i];
else b=aa[i];
if(b>sum) sum = b;
}
return sum;
}
long MaxSumSubMatrix(int m, int n)
{
long sum = 0;
int *b = new int[n];
for(int i = 0 ; i < m ; i++)
{
for(int k = 0 ; k < n ; k++) b[k] = 0;
for(int j = i ; j < m ; j++)
{
for(int k = 0 ; k < n; k++) b[k]+=a[j][k];
long max = MaxSumSubArray(b, n);
if(max > sum) sum = max;
}
}
return sum;
}
int main()
{
int n;
while(cin>>n)
{
for(int i = 0 ; i < n ; i++)
for(int j = 0 ; j < n ; j++)
cin>>a[i][j];
cout<