bzoj 1232 最小生成树

题意:n个点m条双向边,要求去掉一些边仅保留(n-1)条边,每个点有各自的点权,每条边有各自的边权,要求从一个点出发遍历每一个点再回到起点,每经过一次点i,代价就加上一次该点点权,每经过一次边j,代价就加上一次该边的边权。求最小的代价

每一条边对答案的贡献 =  该边的边权*2 + 两端点点权

以此作为它的边权跑最小生成树

然后我们会发现,作为起点的点又额外加了一次,而对于我们求出的最小生成树,无论选哪个点为起点,所需的代价是一样的即新边权的和

我们只需要选择点权最小的点作为起点,最后将答案加上它一次即可

type
        rec=record
            x,y,len:longint;
end;

var
        n,m,tt,ans,tx,ty:longint;
        i               :longint;
        w,father        :array[0..10010] of longint;
        l               :array[0..100010] of rec;

function get_father(x:longint):longint;
begin
   if x=father[x] then exit(x);
   father[x]:=get_father(father[x]);
   exit(father[x]);
end;

procedure sort(ll,rr:longint);
var
        i,j,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,m); ans:=maxlongint;
   for i:=1 to n do
   begin
      read(w[i]);
      if w[i]<ans then ans:=w[i];
   end;
   for i:=1 to n do father[i]:=i;
   for i:=1 to m do
   begin
      read(l[i].x,l[i].y,l[i].len);
      l[i].len:=l[i].len*2+w[l[i].x]+w[l[i].y];
   end;
   sort(1,m); tt:=0;
   for i:=1 to m do
   begin
      tx:=get_father(l[i].x);
      ty:=get_father(l[i].y);
      if tx<>ty then
      begin
         father[tx]:=ty;
         inc(ans,l[i].len);
         inc(tt);
         if tt=n-1 then break;
      end;
   end;
   writeln(ans);
end.
——by Eirlys



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值