题意:题目给出两列数,为了使两列数的和之间的差距(gap)变小,可以交换对应位置的数字,
求出当gap最小的时候,最少的交换次数.
分析:用f[i,j]表示处理完前i对数,差为j的最少交换次数.
注意到f[i]只跟f[i-1]有关,可以用滚动数组.转移类似于填表.
code:
var a,b,d:array[0..1001] of longint;
f:array[0..1,-6000..6000] of longint;
g:array[0..1,-6000..6000] of boolean;
n,i,j,pre,now:longint;
function min(a,b:longint):longint;
begin
if a>b then exit(b); exit(A);
end;
begin
readln(n);
for i:=1 to n do
begin
readln(a[i],b[i]);
d[i]:=a[i]-b[i];
end;
pre:=0;
now:=1;
f[pre,d[1]]:=0;
g[pre,d[1]]:=true;
f[pre,-d[1]]:=1;
g[pre,-d[1]]:=true;
for i:=1 to n-1 do
begin
fillchar(f[now],sizeof(f[now]),0);
fillchar(g[now],sizeof(g[now]),0);
for j:=-6000 to 6000 do
if g[pre,j] then
begin
if abs(j+d[i+1])<=6000 then
if not g[now,j+d[i+1]] then
begin
f[now,j+d[i+1]]:=f[pre,j];
g[now,j+d[i+1]]:=true;
end
else f[now,j+d[i+1]]:=min(f[pre,j],f[now,j+d[i+1]]);
if abs(j-d[i+1])<=6000 then
if not g[now,j-d[i+1]] then
begin
f[now,j-d[i+1]]:=f[pre,j]+1;
g[now,j-d[i+1]]:=true;
end
else f[now,j-d[i+1]]:=min(f[pre,j]+1,f[now,j-d[i+1]]);
end;
pre:=1-pre;
now:=1-now;
end;
for i:=0 to 6000 do
if g[pre,i] then break;
for j:=0 downto -6000 do
if g[pre,j] then break;
if abs(j)<i then writeln(f[pre,j])
else writeln(f[pre,i]);
end.