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].lenx 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 ill 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

bzoj 1601 最小生成树经典题_第1张图片

你可能感兴趣的:(bzoj,最小生成树)