poj 3013

题意:给n个点从1到n标号,下面一行是每个点的权,另外给出m条边,下面是每条边的信息,两个端点+权值,边是无向边。你的任务是选出一些边,使这个图变成一棵树。这棵树的花费是这样算的,1号固定为树根,树中每个双亲节点下面的边都有个单价(即边权),然后单价乘上这条边的下面所有的子孙后代的点权和。

分析:每个点的权都要乘上好几条边的权,就是这个点回到点1的路径上的那些边。要想最小,就是求到到1点的最短路。点数有可能是0。

spfa!!!
const  
  maxe=100000;  
  maxv=2000000;  
  
type  
  arr=record  
    x,y,w,next:int64;  
  end;  
  
var  
  n,m,s,q,nm:longint;  
  ls:array[0..maxe] of longint;  
  a:array[0..maxv] of arr;  
  f:array[0..maxe] of int64;  
  v:array[0..maxe] of int64;  
  d,b:array[0..maxe] of int64;  
  i,j,k,ll:longint;  
  ans,max:int64;  
  
procedure spfa;  
var  
  i,j,k:longint;  
  head,tail:longint;  
begin  
  fillchar(f,sizeof(f),63);  
  max:=f[1];  
  head:=0;  
  tail:=1;  
  v[1]:=1;  
  d[1]:=1;  
  f[1]:=0;  
  repeat  
    head:=head+1;  
    j:=ls[d[head]];  
    while j<>0 do  
      begin  
        with a[j] do  
          begin  
            if f[x]+w<f[y]  
              then  
                begin  
                  f[y]:=f[x]+w;  
                  if v[y]=0  
                    then  
                      begin  
                        tail:=tail+1;  
                        d[tail]:=y;  
                        v[y]:=1;  
                      end;  
                end;  
            j:=next;  
          end;  
      end;  
    v[d[head]]:=0;  
  until head=tail;  
end;  
  
begin  
  readln(nm);  
  for ll:=1 to nm do  
  begin  
  fillchar(ls,sizeof(ls),0);  
  fillchar(d,sizeof(d),0);  
  fillchar(b,sizeof(b),0);  
  fillchar(a,sizeof(a),0);  
  fillchar(v,sizeof(v),0);  
  readln(n,m);  
  for i:=1 to n do  
    read(b[i]);  
  for i:=1 to m do  
    begin  
      with a[i*2-1] do  
        begin  
          readln(x,y,w);  
          next:=ls[x];  
          ls[x]:=i*2-1;  
        end;  
      a[i*2].x:=a[i*2-1].y;  
      a[i*2].y:=a[i*2-1].x;  
      a[i*2].w:=a[i*2-1].w;  
      a[i*2].next:=ls[a[i*2].x];  
      ls[a[i*2].x]:=i*2;  
    end;  
  m:=m*2;  
  spfa;  
  ans:=0;  
  for i:=1 to n do  
    if f[i]=max then break  
                else ans:=f[i]*b[i]+ans;  
  if (f[i]=max) then writeln('No Answer')  
                else writeln(ans);  
  end;  
end.  


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值