原题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.