USACO 6.3.1 Fence Rails dfsid+剪枝

我采用的是dfsid搜索每一个rail来源的board。以下技巧都是针对这种搜索顺序来制定的。

(注:rail是所需要切成的东西,board是供应商提供的原料)

  1. 很容易就能注意到,由于每块rail的价值是相等的——也就是说切小的要比切大的来的划算。那么我们在搜索能否切出i个rail的方案是自然要选最小的i个rail来切。
  2. 经过一些实验可以发现,先切大的rail比先切小的rail更容易提前出解。
  1. 由于r最大可能是1023,但是rail长度的范围却只有0~128,这点提醒了我们有很多rail的长度会是相同的。所以我们要避免冗余,优化搜索顺序。若有rail[i+1]=rail[i],则rail[i+1]对应的board一定大于等于rail[i]对应的board。可以通过这种方法剪掉很多冗余的枝条。
  2. 二分答案
  3. 对于切剩下的board(无法再切下rail),统计一下总和。如果这个值大于board长度的总和减去rail长度的总和,一定无解,可以剪枝。这个剪枝最关键。(这个要基于二分答案)

加上上述优化策略后,程序就能很快出解了。

代码:

{
ID: ymwbegi1
PROG: fence8
LANG: PASCAL
}

var
  n,i,m,tot,ans,l,r,mid,j,rubbish:longint;
  flag:boolean;
  a,b,s,c:array[0..2000] of longint;

procedure sort;
var
  i,j:longint;
begin
  for i:=1 to n-1 do
    for j:=i+1 to n do
      if a[i]>a[j] then
      begin
        a[0]:=a[i];a[i]:=a[j];a[j]:=a[0];
      end;
  for i:=1 to m-1 do
    for j:=i+1 to m do
      if b[i]<b[j] then
      begin
        b[0]:=b[i];b[i]:=b[j];b[j]:=b[0];
      end;
end;

procedure dfs(x,y:longint);
var
  i:longint;
begin
  if x>m then
  begin
    flag:=true;
    exit;
  end;
  if rubbish>tot-s[m]+s[mid-1] then exit;
  if s[m]-s[x-1]>tot-s[x-1]+s[mid-1] then exit;
  for i:=y to n do
    if a[i]>=b[x] then
    begin
      a[i]:=a[i]-b[x];
      if a[i]<b[m] then inc(rubbish,a[i]);
      if b[x]=b[x+1]
        then dfs(x+1,i)
        else dfs(x+1,1);
      if a[i]<b[m] then dec(rubbish,a[i]);
      a[i]:=a[i]+b[x];
      if flag then exit;
    end;
end;

begin
  assign(input,'fence8.in');
  assign(output,'fence8.out');
  reset(input);
  rewrite(output);
  readln(n);
  for i:=1 to n do
  begin
    readln(a[i]);
    tot:=tot+a[i];
  end;
  readln(m);
  c:=a;
  for i:=1 to m do
    readln(b[i]);
  sort;
  for i:=1 to m do
    s[i]:=s[i-1]+b[i];
  l:=1;
  r:=m;
  while s[m]-s[l-1]>tot do inc(l);
  while l<=r do
  begin
    mid:=(l+r) div 2;
    flag:=false;
    rubbish:=0;
    a:=c;
    dfs(mid,1);
    if flag
      then begin
             ans:=m-mid+1;
             r:=mid-1;
           end
      else l:=mid+1;
  end;
  writeln(ans);
  close(input);
  close(output);
end.


你可能感兴趣的:(USACO 6.3.1 Fence Rails dfsid+剪枝)