2016.8.2测试解题报告(submatrix加强版)

Submatrix.

对于这道题,我讲过之后很多同学还是一脸懵逼。而我感觉我对这道题的理解也不是非常的透彻以至于我也没有帮助其他同学A掉这道题。
这次我要重新在这里系统的分析一下这道题,也算是给自己再讲了一遍了。

题目1
题目2
题目3

“对于多维问题,常见的思路是降维”——RujiaLiu。

虽然本题只有二维,但我们也可以把它降到一维试一试。此时问题变成了:对于一个有n个元素的一维序列,求一个长度为m(1≤m≤n)的子序列,使得其这个子序列的分值最小。我们如何用更低代价的算法解决问题呢?可以尝试DP。
事实上,这个问题具有最有子结构无后效性。我们可以把状态定义为“以原序列的第j个元素结尾的长度为i的子序列的分值”。这样,不难列出状态转移方程: f[i,j]:=min{f[i-1,k]+|a[j]-a[k]|}(i≤k

Program submatrix;

constoo=2000000000;//初始化“无限大”的值,这里没有用maxlongint,避免DP时溢出

type data=array[0..20] of longint;

var
i,j,ans,n,m,r,c:longint;
a:array[0..20,0..20] of longint;
rb:data;

function min(x,y:longint):longint;
begin
if x>=y then exit(y) else exit(x)
end;

procedure dp;//动规列
  var
  t,i,k:longint;
  f,hc:array[0..20,0..20] of longint;
  zc:array[0..20] of longint;

begin
//为了后面将整个列放在一起操作,初始化
fillchar(hc,sizeof(hc),0);//横差
fillchar(zc,sizeof(zc),0);//纵差
rb[r+1]:=rb[r];
for i:=1 to m do
 for j:=1 to r do
  zc[i]:=zc[i]+abs(a[rb[j],i]-a[rb[j+1],i]);//每一列中的纵差
for i:=1 to m-1 do
 for j:=i+1 to m do
  for k:=1 to r do
   hc[i,j]:=hc[i,j]+abs(a[rb[k],i]-a[rb[k],j]);//每两列之间的横差fillchar(f,sizeof(f),0);
//------DP主体---------
for i:=1 to m do f[1,i]:=zc[i];
for i:= 2 to c do//枚举阶段
 for j:=i to m do begin//枚举状态
  t:=oo; //t用来临时存储f[i,j]
for k:=i-1 to j-1 do//计算状态(以一个O(m)循环为代价
 t:=min(t,f[i-1,k]+hc[k,j]);
 f[i,j]:=t+zc[j]
end;

for i:=c to m do ans:=min(ans,f[c,i]);
end;


proceduredfs(k,p:longint);//穷搜行
  var i:longint;
begin
 if k=rthendp;
 for i:=p+1 to n do begin
 rb[k+1]:=i;dfs(k+1,i)
 end
end;

Begin

assign(input,'submatrix.in'); reset(input);
assign(output,'submatrix.out');rewrite(output);readln(n,m,r,c);
for i:=1 to n do begin
 for j:=1 to m do
  read(a[i,j]);
readln
end;

ans:=oo;
dfs(0,0);

writeln(ans);

close(input);
close(output)
End.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值