【动规递推】最大数列

来源:互联网 发布:python in用法 编辑:程序博客网 时间:2024/06/05 13:21

最大数列

(sequence.pas/c/cpp)

 

【问题描述】

有一个N项的数列a1, a2 ... aN (|ai| <=10000, 1 <= i <= N)。S定义为

 

你的任务是求S的值,即为求一个序列的两个不相交子序列的最大和。

 

【输入文件】

 

输入文件sequence.in的第一行是一个整数N(2 <= N <= 100000),表示数列的项数。第二行有n个整数,用空格分隔,第i个整数Ai(|Ai| <=10000)是第i位数。

 

【输出文件】

 

输出文件sequence.out包括一行,这一行只包含一个整数,就是S。

 

【样例输入】

 

5

-5 9 -5 11 20

 

【样例输出】

 

40

 

【数据规模】

 

对于30%的数据,保证有n <= 80;

对于70%的数据,保证有n <= 10000;

对于全部的数据,保证有n <= 100000。

 

先看求一个最大子列的做法:

Sum := 0; min := 0;For i := 1 to n do  begin     sum := sum + a[i];     if sum – min > ans then ans := sum – min;     if min < sum then sum := min;  end;

 

上述算法实质:动态规划,复杂度O(N)

 

下面看求两个子列的情况:
  两个子列不相交,故一定存在一个断点,我们枚举断点,然后分别对左边数列和右边的数列套用上述求一个最大子列的方法。算法复杂度O(N2)
 
 
需要进行优化,我们可以一开始就求出所有前缀子列的最大子列和所有后缀子列的最大子列,然后存放在一个数组里,后部计算则可直接调用。
For I := 1 to n-1 do ans := max(ans,left[i]+right[i+1]);

 

因为求一个最大子列的方法事实上是在递推,所以left和right数组都可以在O(N)的时间内求出。整个算法复杂度也是O(N)
 
 
Pascal Code
program sequence;var  n:longint;  a,s,ss,f:array[0..100000+10] of longint;procedure init;begin  assign(input,'sequence.in');  assign(output,'sequence.out');  reset(input);  rewrite(output);end;procedure outit;begin  close(input);  close(output);  halt;end;procedure readdata;var  i:longint;begin  read(n);  for i:=1 to n do  begin    read(a[i]);    s[i]:=s[i-1]+a[i];  end;  for i:=n downto 1 do ss[i]:=ss[i+1]+a[i];end;procedure main;var  min,max,ans:longint;  i:longint;begin  min:=0;f[0]:=-maxlongint;  for i:=1 to n do//求左区间的最大值  begin    f[i]:=s[i]-min;    if f[i]<f[i-1] then f[i]:=f[i-1];    if min>s[i] then min:=s[i];  end;  min:=0;max:=-maxlongint;ans:=-maxlongint;  for i:=n downto 2 do//求右区间的最大值  顺便把左区间相加  找出最佳答案  begin       //后面用到 f[i-1] 所以只能 downto 2    if max<ss[i]-min then max:=ss[i]-min;    if max+f[i-1]>ans then ans:=max+f[i-1];    if min>ss[i] then min:=ss[i];  end;  writeln(ans);end;begin  init;  readdata;  main;  outit;end.

 

 

原创粉丝点击