算法:图论(最小生成树)
分析:题目大意在TYVJ上说的不是很清楚,这里再说明一下,就是说给出了一个不完全图(最小生成树),在这个不完全图中添加边使之成为完全图,同时添加完边之后必须能保证不破坏原来的最小生成树。
可以采用kruskal解决,我们知道kruskal的最终目的是将两棵最小生成树合成一棵,设第一棵树中点的个数为x,第二课树中点的个数为y,那么除去他们之间连接的最短的边,一定还有x*y-1条边,所以就让这x*y-1条边的权值为两颗树之间连接的最短的边的权值+1。
一个更通俗的解释就是,不在生成树内的边一定大于在生成树内的边。
分析:题目大意在TYVJ上说的不是很清楚,这里再说明一下,就是说给出了一个不完全图(最小生成树),在这个不完全图中添加边使之成为完全图,同时添加完边之后必须能保证不破坏原来的最小生成树。
可以采用kruskal解决,我们知道kruskal的最终目的是将两棵最小生成树合成一棵,设第一棵树中点的个数为x,第二课树中点的个数为y,那么除去他们之间连接的最短的边,一定还有x*y-1条边,所以就让这x*y-1条边的权值为两颗树之间连接的最短的边的权值+1。
一个更通俗的解释就是,不在生成树内的边一定大于在生成树内的边。
最后用所有边的边权和减去最小生成树的边权和就是修建道路的费用和。
program P1391;
const
maxn=6000;
type
atp=record
x,y,dis:longint;
end;
var
ans,sum,total,ii,n:longint;
a:array [0..maxn] of atp;
v,fa:array [0..maxn] of longint;
procedure init;
var
i,x,y,dis:longint;
begin
ans:=0;
sum:=0;
readln(n);
for i:=1 to n-1 do
begin
fa[i]:=i;
v[i]:=1;
readln(x,y,dis);
inc(sum,dis);
a[i].x:=x;
a[i].y:=y;
a[i].dis:=dis;
end;
fa[n]:=n;
v[n]:=1;
end;
function getf(x:longint):longint;
begin
if fa[x]=x then exit(x)
else
begin
fa[x]:=getf(fa[x]);
exit(fa[x]);
end;
end;
procedure qsort(l,r:longint);
var
i,j,m:longint;
t:atp;
begin
i:=l;
j:=r;
m:=a[(l+r) shr 1].dis;
repeat
while a[i].dis<m do inc(i);
while a[j].dis>m do dec(j);
if i<=j then
begin
t:=a[i];
a[i]:=a[j];
a[j]:=t;
inc(i);
dec(j);
end;
until i>j;
if i<r then qsort(i,r);
if l<j then qsort(l,j);
end;
procedure main;
var
i,xx,yy,dis:longint;
begin
for i:=1 to n-1 do
begin
xx:=getf(a[i].x);
yy:=getf(a[i].y);
dis:=a[i].dis;
inc(ans,(v[xx]*v[yy]-1)*(dis+1)+dis);
fa[yy]:=xx;
inc(v[xx],v[yy]);
end;
end;
begin
assign(input,'P1391.in'); reset(input);
assign(output,'P1391.out'); rewrite(output);
readln(total);
for ii:=1 to total do
begin
init;
qsort(1,n-1);
main;
writeln(ans-sum);
end;
close(input); close(output);
end.
本文详细解析了图论中最小生成树的概念及其应用,并通过kruskal算法解决了一个特定问题:如何在不完全图中添加边使之成为完全图,同时保证不破坏原有的最小生成树。通过分析边权的特性,最终计算出修建道路的费用。
532

被折叠的 条评论
为什么被折叠?



