最大子矩阵(SCOI2005)

本文通过动态规划的方法解决了一个涉及矩阵求和的问题。作者最初忽略了列数限制,导致复杂度提高。通过预处理和状态转移方程,最终简化了解题过程。
算法:DP
 
分析:第一次看题时不仔细,竟然忽略了列数小于等于2这个限制,导致一直在想特别复杂的算法,后来才发现在列数很小的情况下这到题还是比较容易想的。
      先预处理一下第一列前i列的和和第二列前j列的和和前i行的和。
      可以设f[i,j,k]表示计算到第i个矩形时第一列到j,第二列到k的最大矩阵和,则f[i,j,k]=max(f[i,j-1,k],f[i,j,k-1],f[i-1,x,k]+a2[j,1]-a2[x,1],f[i-1,j,x]+a2[k,2]-a2[x,2])(限制条件为j<>k)  
                                                                             f[i,j,k]=max(f[i,j-1,k],f[i,j,k-1],f[i-1,x,k]+a2[j,1]-a2[x,1],f[i-1,j,x]+a2[k,2]-a2[x,2],f[i-1,x,x]+s2[j]-s2[x])(限制条件为j=k)
      按照以上思路将题目总共分成两类,一类是列数=1的,一类是列数<>1的,分开计算一下就行了。
       

思考:对DP有那么点感觉了,感觉就是DP就把题目中说的那些条件扯上关系,然后用一个状态表示出来就行了。个人认为矩阵类似问题通常跟行或列扯上关系。                          

program BZOJ1084;



const

 maxn=100;

 maxk=10;



var

 n,m,divide:longint;

 f1:array [0..maxk,0..maxn] of longint;

 f2:array [0..maxk,0..maxn,0..maxn] of longint;

 a1,s:array [0..maxn] of longint;

 a2:array [0..maxn,1..2] of longint;

 

function max(x,y:longint):longint;

begin

 if x>y then exit(x) else exit(y);

end;

 

procedure main;

var

 i,j,k,l,maxx:longint;

begin

 readln(n,m,divide);

 if m=1 then

  begin

   for i:=1 to n do

    begin

     readln(a1[i]);

     inc(a1[i],a1[i-1]);

    end;

   for i:=1 to divide do

    begin

     for j:=1 to n do

      begin

       maxx:=f1[i,j-1];

       for k:=1 to j-1 do maxx:=max(maxx,f1[i-1,k]+a1[j]-a1[k]);

       f1[i,j]:=maxx;

      end;

    end;

   writeln(f1[divide,n]);

  end

 else

  begin

   for i:=1 to n do

    begin

     readln(a2[i,1],a2[i,2]);

     s[i]:=s[i-1]+a2[i,1]+a2[i,2];

     inc(a2[i,1],a2[i-1,1]);

     inc(a2[i,2],a2[i-1,2]);

    end;

   for i:=1 to divide do

    begin

     for j:=1 to n do

      begin

       for k:=1 to n do

        begin

         maxx:=f2[i,j,k];

         maxx:=max(maxx,f2[i,j-1,k]);

         for l:=1 to j-1 do maxx:=max(maxx,f2[i-1,l,k]+a2[j,1]-a2[l,1]);

         maxx:=max(maxx,f2[i,j,k-1]);

         for l:=1 to k-1 do maxx:=max(maxx,f2[i-1,j,l]+a2[k,2]-a2[l,2]);

         if j=k then for l:=1 to j-1 do maxx:=max(maxx,f2[i-1,l,l]+s[j]-s[l]);

         f2[i,j,k]:=maxx;

        end;

      end;

    end;

   writeln(f2[divide,n,n]);

  end;

end;



begin

 assign(input,'BZOJ1084.in'); reset(input);

 assign(output,'BZOJ1084.out'); rewrite(output);

 

 main;

 

 close(input); close(output);

end.


                   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值