poj3013

【题意】

给定v个点的重量,并给定e条边,每条边具有一个权值,在e条边中选v-1条边使这v个点成为一棵树,设一棵树的代价为(每棵子树节点重量和其子树根到父节点的边的权值的乘积)之和,求以1为根节点的树的最小代价

【输入】

多组数据,第一行为一个数t,表示有t组数据

接下来每组数据第一行两个数v、e(<=50000)意义如上

接下来一行v个数描述各个点的重量

之后的e行表示e条边及其权值

【输出】

对于每组数据,输出一个数字表示其以1为根节点的树的最小代价


求以1为原点的各点最短路径,答案即为(各点【最短路径*重量】之和)

需要注意边是双向的,最多有100000条边


program poj3013;
var
  all,tot,n,e,t,i,j,k,u,v,c,o:longint;
  ans:int64;
  l,r:array [0..1] of longint;
  next,root,point,cost,w,dis:array [0..150001] of int64;
  dl:array [0..1,-150001..150001] of longint;

procedure spfa;
begin
  fillchar(dis,sizeof(dis),63);
  o:=0;
  l[o]:=0;
  r[o]:=0;
  dl[o,0]:=1;
  dis[1]:=0;
  while l[o]<=r[o] do
    begin
      o:=1-o;
      l[o]:=0;
      r[o]:=-1;
      for i:=l[1-o] to r[1-o] do
        begin
          k:=root[dl[1-o,i]];
          while k<>0 do
            begin
              if dis[dl[1-o,i]]+cost[k]<dis[point[k]] then
                begin
                  dis[point[k]]:=dis[dl[1-o,i]]+cost[k];
                  if (l[o]<=r[o])and(dis[point[k]]<dis[dl[o,l[o]]]) then
                    begin
                      dec(l[o]);
                      dl[o,l[o]]:=point[k];
                    end
                                                                    else
                    begin
                      inc(r[o]);
                      dl[o,r[o]]:=point[k];
                    end

                end;
              k:=next[k];
            end;
        end;
    end;
end;


procedure connect (u,v,c:longint);
begin
  inc(tot);
  point[tot]:=v;
  cost[tot]:=c;
  next[tot]:=root[u];
  root[u]:=tot;
end;

begin
  read(t);
  while t>0 do
    begin
      read(n,e);
      for i:=1 to n do
        read(w[i]);
      fillchar(root,sizeof(root),0);
      tot:=0;
      for i:=1 to e do
        begin
          read(u,v,c);
          connect(u,v,c);
          connect(v,u,c);
        end;
      spfa;
      ans:=0;
      for i:=1 to n do
        begin
          if dis[i]=dis[0] then break;
          ans:=ans+dis[i]*w[i];
        end;
      if dis[i]=dis[0] then writeln('No Answer')
                       else writeln(ans);
      dec(t);
    end;
end.



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值