算法: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的,分开计算一下就行了。
分析:第一次看题时不仔细,竟然忽略了列数小于等于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.
本文通过动态规划的方法解决了一个涉及矩阵求和的问题。作者最初忽略了列数限制,导致复杂度提高。通过预处理和状态转移方程,最终简化了解题过程。
113

被折叠的 条评论
为什么被折叠?



