1. 程式人生 > >bzoj 1601 最小生成樹經典題

bzoj 1601 最小生成樹經典題

題意:n塊農田,全部灌水。有兩種方式:(1)在第n塊天上花費wi建造一個水庫(2)從另一塊田j花費Pij引水,求最小花費

MST好題

如果沒有可以建造水庫的條件,那麼就是一個最小生成樹,沒毛病╮(╯_╰)╭

然而加上這個條件以後,相當於可以自己向自己引水花費為wi

加一個超級源點,並向n個點連邊為wi,然後對這n+1個點跑最小生成樹即可

程式設計難度為0,但是想到超級源點的難度還是不小的,超級源點在MST、網路流、差分約束系統...應用還是滿廣的還很靈活

type
        rec=record
            a,b,len:longint;
end;

var
        n,m,ta,tb,ans   :longint;
        ss,tt           :longint; 
        f               :array[0..90010] of longint;
        l               :array[0..50010] of rec;
        i,j             :longint;
        map             :array[0..310,0..310] of longint;
function get_father(x:longint):longint;
begin
   if x=f[x] then exit(x);
   f[x]:=get_father(f[x]);
   exit(F[x]);
end;

procedure sort(ll,rr:longint);
var
        i,j:longint;
        x:longint;
        y:rec;
begin
   i:=ll; j:=rr; x:=l[(ll+rr)>>1].len;
   while (i<=j) do
   begin
      while l[i].len<x do inc(i);
      while l[j].len>x do dec(j);
      if (i<=j) then
      begin
         y:=l[i]; l[i]:=l[j]; l[j]:=y;
         inc(i); dec(j);
      end;
   end;
   if i<rr then sort(i,rr);
   if j>ll then sort(ll,j);
end;

begin
   read(n); ss:=n+1;
   for i:=1 to n+1 do f[i]:=i;
   for i:=1 to n do
   begin
      read(l[i].len);
      l[i].a:=ss; l[i].b:=i;
   end;
   m:=n;
   for i:=1 to n do
     for j:=1 to n do read(map[i,j]);
   for i:=1 to n do
     for j:=i+1 to n do
     begin
        inc(m);
        l[m].len:=map[i,j];
        l[m].a:=i; l[m].b:=j;
     end;
   sort(1,m);
   tt:=0;
   for i:=1 to m do
   begin
      ta:=get_father(l[i].a);
      tb:=get_father(l[i].b);
      if (ta<>tb) then
      begin
         inc(tt);
         f[ta]:=tb;
         inc(ans,l[i].len);
         if tt=n then break;
      end;
   end;
   writeln(ans);
end.
——by EIrlys