【Dynamic Programming】从最大连续子段和到最优子矩阵

【前言】

°朱老湿上次提了一句这个,其实挺水的,但还算挺经典的吧。简略说说接着刷题去…

【最大连续字段和】

°Problem:对{an}数列,求最大的一段子序列的和。

°Solution:F[i]←max{F[i-1]+a[i],a[i]}(1<=i<=n)

°Answer:Max{F[i]}(1<=i<=n)

°Code:

  1: Program Max_1(input,output);
  2:   var n,i,ans:Longint;
  3:       F,a:array[0..100]of longint;
  4:   function max(a,b:Longint):Longint;
  5:     begin
  6:       if a>b then exit(a) else exit(b);
  7:     end;
  8:   begin
  9:     readln(n);
 10:     for i:=1 to n do read(a[i]);ans:=-19940805;
 11:     for i:=1 to n do
 12:       begin
 13:         F[i]:=max(F[i-1]+a[i],a[i]);
 14:         if ans<F[i] then ans:=F[i];
 15:       end;
 16:     writeln(ans);
 17:   end.

°Extended:在一个长度为n的数列{An}中,求m个连续子序列,使得这m个连续子序列的和最大,且m个子序列无公共元素。

°Solution:解决类似的问题,我们可以利用“加一维”的思想利用动态规划来解决。

F[i,j]表示数列前j个元素中,i个无公共元素的子序列的最大和,且必须包含第j个元素。

F[i,j]=max{F[i,j-1]+a[j](i<=j<=n),F[i-1,k]+a[j](i-1<=k<=j-1)} 

时间复杂度为O(n^3)

°Code:

  1: Program Max_2(input,output);
  2:   var n,m,ans,i,j,k:longint;
  3:       a:array[1..100]of longint;
  4:       F:array[0..100,0..100]of longint;
  5:   Function max(a,b:longint):longint;
  6:      begin
  7:        if a>b then exit(a) else exit(b);
  8:      end;
  9:   begin
 10:     readln(n,m);
 11:     for i:=1 to n do read(a[i]);
 12:     for i:=1 to m do
 13:       for j:=i to n do
 14:          begin
 15:            F[i,j]:=F[i,j-1]+a[j];
 16:            for k:=i-1 to j-1 do
 17:              F[i,j]:=max(F[i-1,k]+a[j],F[i,j]);
 18:          end; 
 19:     ans:=-19940805;
 20:     for i:=1 to n do 
 21:       if F[m,i]>ans then ans:=F[m,i];
 22:     writeln(ans);
 23:   end.

【最优子矩阵】

°Problem:对n×m的矩阵,求最大的一个子矩阵的和。

°Solution:枚举边界,将矩阵压缩成线性,用最大字段和出解

°Code:

  1: Program Max_Matrix(input,output);
  2:   var a:array[1..100,1..100]of longint;
  3:       aa,F:array[1..100]of longint;
  4:       i,j,n,m,up,down,ans:longint;
  5:   Function max(a,b:longint):Longint;
  6:     begin
  7:       if a>b then exit(a) else exit(b);
  8:     end;
  9:   Procedure Zip(up,down:longint);
 10:     begin
 11:       fillchar(aa,sizeof(aa),0);
 12:       for i:=1 to m do
 13:         for j:=up to down do 
 14:           inc(aa[i],a[i,j]);
 15:     end;
 16:   begin
 17:     readln(n,m);
 18:     for i:=1 to n do
 19:       for j:=1 to m do
 20:         read(a[i,j]);
 21:     ans:=-19940805;
 22:     for up:=1 to n do
 23:       for down:=1 to n do
 24:         begin
 25:           Zip(up,down);
 26:           fillchar(F,sizeof(F),0);
 27:           for i:=1 to m do
 28:             begin
 29:               F[i]:=max(F[i-1]+aa[i],aa[i]);
 30:               if F[i]>ans then ans:=F[i];
 31:             end;
 32:         end;
 33:     writeln(ans);
 34:   end.

°Extended:在一个n*m二维的矩阵中,确定两个小的矩阵,使这两个小矩阵中所有元素的总和最大,且两个矩阵无公共元素。

这个不会…真心复杂…分类讨论+枚举伤不起

【例题】

°Vijos 1057 House Building(这个不是最优子矩阵,但是很有趣啊~呵呵)

描述 Description
  有面积为n*m的一大块土地,要在这块土地上建造一所房子,这个房子必须是正方形的。
  但是,这块土地上面有很多不平坦的地方,这些地方不能用来盖房子。
  他希望找到一块最大的正方形来盖房子。
输入格式 Input Format
  输入文件第一行为两个整数n,m(1<=n,m<=1000)
  接下来n行,每行m个数字,用空格隔开。
  0表示该块土地不平坦,1表示该块土地完好。
输出格式 Output Format
  一个整数,最大正方形的边长。
样例输入 Sample Input
  4 4
  0 1 1 1
  1 1 1 0
  0 1 1 0
  1 1 0 1
样例输出 Sample Output
 2

°Solution:F[i,j]表示以(i,j)为右下角的最大正方形的边长。

F[i,j]←min{F[i-1,j],F[i,j-1],F[i-1,j-1]}+1

注意方程要取min:

***************

***************

***************

***************

我们设f[i-1, j]=3,首先我们可以保证红色区域为1,再设f[I,j-1]=2 那么绿色区域为1

***************

***************

***************

***************

我们设f[i-1, j-1]=3,那么蓝色区域为1.

***************

***************

***************

***************

很明显,我们应该选取最小值,才可以确定以(I,j)为右下角的最大正方形长度。

这是一个经典的由方案合理性确定opt的问题。

°Code:

Program HouseBuilding(input,output);
  var F,a:array[0..1000,0..1000]of integer;
      n,m,i,j,ans:integer;
  Function min(a,b,c:integer):integer;
    begin
      min:=a;if b<min then min:=b;if c<min then min:=c;
    end;
  begin
    readln(n,m);
    for i:=1 to n do 
      for j:=1 to m do
        read(a[i,j]);
    ans:=-19940805;
    for i:=1 to n do
      for j:=1 to m do
        if a[i,j]=1 then 
          begin
            F[i,j]:=min(F[i-1,j],F[i,j-1],F[i-1,j-1])+1;
            if F[i,j]>ans then ans:=F[i,j];
          end;
    writeln(ans);
  end.

°Strengthed House Building(可行性最优子矩阵)

描述 Description
  n*m的矩形,有的位置被禁止选取,可以选取的格子价值不同。
  找出一个最大的  矩形平地,使得这个矩形合法且价值最大。
输入 Input
  从文件读入数据。第一行有两个整数n,m。
  第i+1行的第j个数表示a[i][j].
  如果这个数为0,则表示这个位置的格子被禁止。
  1≤n,m≤1000 0≤a[i][j]≤255 保证输入数据都是整数。
输出 Output
  最大的利用价值。
输入样例
  3 4
  1 2 3 4
  5 0 6 3
  10 3 4 0
输出样例
  17

°地精工程师(价值可变最优子矩阵)

【跋】

没啥说的,就这样吧

posted @ 2011-09-28 10:12  Loongint  阅读(381)  评论(0编辑  收藏  举报