[USACO 1.3.2] Barn Repair

[題目描述]

Barn Repair

修理牛棚

        在一個暴風雨的夜晚,農民約翰的牛棚的屋頂、門被吹飛了。 好在許多牛正在度假,所以牛棚沒有住滿。 剩下的牛一個緊挨着另一個被排成一行來過夜。 有些牛棚裏有牛,有些沒有。 所有的牛棚有相同的寬度。 自門遺失以後,農民約翰很快在牛棚之前豎立起新的木板。 他的新木材供應者將會供應他任何他想要的長度,但是供應者只能提供有限數目的木板。 農民約翰想將他購買的木板總長度減到最少。 給出 M(1<= M<=50),可能買到的木板最大的數目;S(1<= S<=200),牛棚的總數;C(1 <= C <=S) 牛棚裏牛的數目,和牛所在的牛棚的編號stall_number(1 <= stall_number <= S),計算攔住所有有牛的牛棚所需木板的最小總長度。 輸出所需木板的最小總長度作爲的答案。 

PROGRAM NAME: barn1 

INPUT FORMAT

第 1 行: M , S 和 C(用空格分開)
第 2 到 C+1行: 每行包含一個整數,表示牛所佔的牛棚的編號。

SAMPLE INPUT (file barn1.in) 

4 50 18
3
4
6
8
14
15
16
17
21
25
26
27
30
31
40
41
42
43

OUTPUT FORMAT

單獨的一行包含一個整數表示所需木板的最小總長度。 

SAMPLE OUTPUT (file barn1.out) 

25 

[ 一種最優的安排是用板攔住牛棚3-8,14-21,25-31,40-43.]


[解題思路]

可以這樣想,先將一塊長度爲S的木板覆蓋所有牛棚,可以每次將木塊分裂,就相當於多用一塊木板了,要使所有木塊長度總和最小,貪心的想下,必定是每次分裂的時候取間隔最大的。於是算法就出來了,將所有間隔按長度降序排序,除去前面M-1個即可。特別注意的是,兩端的間隔是不計入排序的,因爲完全不必用木板去蓋。

由於數據比較水,所以還想了一個複雜度較高的DP。

記F[i,j]表示修到第i個位置,用j塊木板的最小長度。

則,當i不需要覆蓋時,F[i,j]=min(F[i,j],F[i-1,j]);當i需要覆蓋時,F[i,j]=min(F[i,j],F[k,j-1]+i-k)。

總複雜度是O(S^2*M),依舊可以0.00s過...


[Code]

貪心:

{
ID: zane2951
PROG: barn1
LANG: PASCAL
}

program barn1;
var
   w:array[0..211] of longint;
   f:array[0..211] of boolean;
   n,m,s,x,i,t,len,ans,st,ed:longint;

//-----------qs------------
procedure qs(ss,tt:longint);
var
   i,j,ce,tmp:longint;

begin
   i:=ss; j:=tt; ce:=w[(i+j)>>1];
   repeat
      while w[i]>ce do inc(i);
      while w[j]<ce do dec(j);
      if i<=j then
         begin
            tmp:=w[i]; w[i]:=w[j]; w[j]:=tmp;
            inc(i); dec(j);
         end;
   until i>j;
   if i<tt then qs(i,tt); if ss<j then qs(ss,j);
end;

//-----------min-----------
function min(a,b:longint):longint;
begin
   if a<b then exit(a) else exit(b);
end;

//----------main-----------
begin
   assign(input,'barn1.in'); reset(input);
   assign(output,'barn1.out'); rewrite(output);
   readln(n,m,s);
   for i:=1 to s do begin readln(x); f[x]:=true; end;
   for i:=1 to m do if f[i] then begin st:=i; break; end;
   for i:=m downto 1 do if f[i] then begin ed:=i; break; end;
   t:=0; len:=0; f[m+1]:=true;
   for i:=st to ed do
      if f[i] then if len>0 then begin inc(t); w[t]:=len; len:=0; end
         else else inc(len);
   qs(1,t); ans:=ed-st+1;
   for i:=1 to min(n-1,t) do ans:=ans-w[i];
   if ans>=0 then writeln(ans) else writeln(0);
   close(input); close(output);
end.
DP:

{
ID: zane2951
PROG: barn1
LANG: PASCAL
}

program barn1;
var
   f:array[0..211,0..51] of longint;
   g:array[0..211] of boolean;
   n,m,s,i,x,ans,j,k,tmp,ce,st,ed:longint;

//-----------min-----------
function min(a,b:longint):longint;
begin
   if a<b then exit(a) else exit(b);
end;

//----------main-----------
begin
   assign(input,'barn1.in'); reset(input);
   assign(output,'barn1.out'); rewrite(output);
   readln(n,m,s);
   for i:=1 to s do begin readln(x); g[x]:=true; end;
   for i:=1 to m do if g[i] then begin st:=i; break; end;
   for i:=m downto 1 do if g[i] then begin ed:=i; break; end;
   fillchar(f,sizeof(f),127);
   for i:=0 to n do f[st-1,i]:=0;
   for j:=1 to n do
      for i:=st to ed do
         if not g[i] then f[i,j]:=min(f[i,j],f[i-1,j])
            else
               begin
                  ce:=maxlongint;
                  for k:=st-1 to i-1 do
                     if f[k,j-1]+i-k<ce then ce:=f[k,j-1]+i-k;
                  f[i,j]:=min(f[i,j],ce);
               end;
   ans:=maxlongint;
   for i:=1 to n do ans:=min(ans,f[ed,i]);
   writeln(ans);
   close(input); close(output);
end.
發佈了41 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章