首页 > 代码库 > 【NOIP2014】子矩阵

【NOIP2014】子矩阵

这题如果按暴力做只有一半分,最大时间复杂度为O(C(8,16)*C(8,16)); 很容易算出超时;

我们可以发现如果直接dp会很难想,但是知道选哪几行去dp就很好写状态转移方程:

     dp[i][j]=min(dp[i][j],dp[k][j-1]+a[i]+b[k][i]);

其中dp[i][j]表示 前i列里选j列的子矩阵最大分值

     a[i]表示 第i列选到的行的总差值

     b[k][i]表示选到的每一行第k列和第i列之间的差值

我们只要枚举 行 然后dp一次,取最小值即可 这样最大时间复杂度就成了O(C(8,16)*n3);

最后附上我弱弱的pascal代码: 

 1 var 2   i,j,k,n,m,n1,m1,ans:longint; 3   dp,a,f:array[0..16,0..16] of longint; 4   hc:array[0..16,1..16,1..16] of longint; 5   b,lc:array[0..17] of longint; 6 function min(a,b:longint):longint; 7  begin 8   if a>b then min:=b 9          else min:=a;10  end;11 procedure ddp;12  var13   i,j,k,max:longint;14  begin15   fillchar(f,sizeof(f),0);16   fillchar(lc,sizeof(lc),0);17   fillchar(dp,sizeof(dp),0);18   for i:=1 to m do19    for j:=1 to n1-1 do20     lc[i]:=lc[i]+abs(a[b[j+1],i]-a[b[j],i]);21   for i:=1 to m do22    for j:=i+1 to m do23     for k:=1 to n1 do24      f[i,j]:=f[i,j]+hc[b[k],i,j];25   for i:=1 to m do26    dp[i,1]:=lc[i];27   for i:=2 to m do28    for j:=2 to m1 do29     if i>=j then30               begin31                dp[i,j]:=maxlongint;32                for k:=j-1 to i-1 do33                 dp[i,j]:=min(dp[i,j],dp[k,j-1]+lc[i]+f[k,i]);34               end;35   for i:=m1 to m do36    if dp[i,m1]<ans then ans:=dp[i,m1];37  end;38 procedure jw(ii:longint);39  begin40   inc(b[ii]);41   if ii>=0 then42    if b[ii]>(n-n1+ii) then43                          begin44                           jw(ii-1);45                           b[ii]:=b[ii-1]+1;46                          end;47  end;48 begin49   read(n,m,n1,m1);50   for i:=1 to n do51    for j:=1 to m do52     begin53      read(a[i,j]);54      for k:=1 to j-1 do55       hc[i,k,j]:=abs(a[i,j]-a[i,k]);56     end;57   for i:=1 to n1 do58    b[i]:=i;59   ans:=100000000;60   while b[0]=0 do61    begin62     ddp;63     jw(n1);64    end;65   write(ans);66 end.

 

【NOIP2014】子矩阵