zoukankan      html  css  js  c++  java
  • 【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

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

    【跋】

    没啥说的,就这样吧

  • 相关阅读:
    mysql关联更新表
    List Slider
    mysql同步复制报Slave can not handle replication events with the checksum that master 错误
    ie11 .pac代理脚本无法使用的问题2
    centos6.5安装配置nginx+php+mysql+httpsqs+ttserver+redis
    Linux 磁盘坏道检测和修复
    ie11 .pac代理脚本无法使用的问题
    javascript取前n天的日期两种方法
    javascript位操作符右移>>>的妙用
    Angular表单验证
  • 原文地址:https://www.cnblogs.com/Loongint/p/2193878.html
Copyright © 2011-2022 走看看