I and OI
Past...

题意:题目给出两列数,为了使两列数的和之间的差距(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.

posted on 2011-08-10 16:10  exponent  阅读(776)  评论(1编辑  收藏  举报