【JZOJ4686】 通讯

原题HDU3072 以及 JZOJ4686
一道我改了好久的题目。
大概题意就是求从一个点走到全部点所需要的最小总边权,有点像MST模型的说。
但是同一个强连通分量里面的点互相连的走过代价为0。
容易想到Tarjan求强联通分量然后缩点的做法,这样处理图就方便多了。
对于这个和MST差不多的图,我们可以用SPFA来跑一遍最短路,同时更新答案。
其实还有一种贪心做法的说(* ̄︶ ̄)y
因为答案保证有解,所以说每个点都是联通的,也就意味着每个点都会有入边
我们可以贪心地为每个点选择一条权值最低的入边,直接统计答案即可。

代码略长

type
    arr=array[1..100000] of longint;
    edge=record
        x,y,cost,next:longint;
    end;
var
    st:array[1..500000] of longint;
    g,f:array[1..100000] of Edge;
    p,v:array[1..100000] of boolean;
    e,ef,dfn,low,stk,blk,cst,dis:arr;
    n,m,t,x,y,c,i:longint;
    ti,pl,top,hd,tl:longint;
    ans:int64;
function min(a,b:longint):longint;
begin
    if a<b then exit(a)
    else exit(b);
end;
procedure add(x,y,c:longint);
begin
    inc(t);
    g[t].x:=x;
    g[t].y:=y;
    g[t].cost:=c;
    g[t].next:=e[x];
    e[x]:=t;
end;
procedure addEdge(x,y,c:longint);
begin
    inc(t);
    f[t].x:=x;
    f[t].y:=y;
    f[t].cost:=c;
    f[t].next:=ef[x];
    ef[x]:=t;
end;
procedure dfs(x:longint);
var
        i,y:longint;
begin
        inc(ti);
        v[x]:=true;
        dfn[x]:=ti;
        low[x]:=ti;
        inc(top);
        stk[top]:=x;
        p[x]:=true;
        i:=e[x];
        repeat
                y:=g[i].y;
                if (v[y])and(p[y]) then
                low[x]:=min(low[x],dfn[y])
                else if (not(v[y]))and(not(p[y])) then
                begin
                        dfs(y);
                        low[x]:=min(low[x],low[y]);
                end;
                i:=g[i].next;
        until i=0;
        if low[x]=dfn[x] then
        begin
                inc(pl);
                repeat
            blk[stk[top]]:=pl;
                        p[stk[top]]:=false;
                        dec(top);
                until stk[top+1]=x;
        end;
end;
procedure fillc;
begin
    fillchar(g,sizeof(g),0);
    fillchar(e,sizeof(e),0);
    fillchar(f,sizeof(f),0);
    fillchar(ef,sizeof(ef),0);
    fillchar(dfn,sizeof(dfn),0);
    fillchar(low,sizeof(low),0);
    fillchar(stk,sizeof(stk),0);
    fillchar(blk,sizeof(blk),0);
    fillchar(v,sizeof(v),0);
    fillchar(p,sizeof(p),0);
    fillchar(cst,sizeof(cst),$7f);
end;
begin
while true do
begin
    t:=0;
    fillc;
    readln(n,m);
    if n=0 then exit;
    for i := 1 to m do
    begin
        readln(x,y,c);
        inc(x);inc(y);
        add(x,y,c);
        end;
    pl:=0;top:=0;
        dfs(1);
    t:=0;
    for i := 1 to m do
    begin
        x:=blk[g[i].x];
        y:=blk[g[i].y];
        if x<>y then addEdge(x,y,g[i].cost);
    end;
    fillchar(p,sizeof(p),0);
    fillchar(dis,sizeof(dis),255);
    hd:=0;tl:=1;st[1]:=blk[1];dis[blk[1]]:=0;ans:=0;p[blk[1]]:=true;
    while hd<tl do
    begin
        inc(hd);
        i:=ef[st[hd]];
        while i<>0 do
        begin
            y:=f[i].y;
            if dis[y]=-1 then
            begin
                dis[y]:=f[i].cost;
                ans:=ans+dis[y];
                if not(p[y]) then
                begin
                    p[y]:=true;
                    inc(tl);
                    st[tl]:=y;
                end;
            end else
            if dis[y]>f[i].cost then
            begin
                ans:=ans-dis[y]+f[i].cost;
                dis[y]:=f[i].cost;
                if not(p[y]) then
                begin
                    p[y]:=true;
                    inc(tl);
                    st[tl]:=y;
                end;
            end;
            i:=f[i].next;
        end;
        p[st[hd]]:=false;
    end;
    writeln(ans);
end;
end.
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值