usaco 3.1 agrinet 2008.7.16
{
ID:
PROG: agrinet
LANG: PASCAL
}
program pppp;
const
maxn=100;
maxe=maxn*maxn;
type
edge=record
a,b :longint; //边的2个顶点
len :longint; //边的长度
end;
var
edges :array[0..maxe]of edge; //保存所有边的信息
p,r :array[0..maxn]oflongint; //p[i]保存i的父亲节点,r用来实现Union-Find的rank启发式
n,e,j,xs :longint; //n为顶点数,e为边数
f1,f2:text;
map:array[1..maxn,1..maxn]of 0..1;
procedure swap(a,b:longint); //交换
begin
edges[0]:=edges[a];
edges[a]:=edges[b];
edges[b]:=edges[0];
end;
procedure quicksort(l,r:longint); //快速排序
var
x,i,j :longint;
begin
x:=edges[random(r-l+1)+l].len;
i:=l;j:=r;
repeat
while edges[i].len<x do inc(i);
while edges[j].len>x do dec(j);
if i<=j then
begin
swap(i,j);
inc(i);dec(j);
end
until i>j;
ifl<j then quicksort(l,j);
ifi<r then quicksort(i,r);
end;
procedure init;
var
i :longint;
begin
assign(f1,'agrinet.in');reset(f1);
assign(f2,'agrinet.out');rewrite(f2);
readln(f1,n);e:=0;
fillchar(map,sizeof(map),0);
fori:=1 to n do
for j:=1 to n do
begin
read(f1,xs);
if(xs<>0)and(map[i,j]=0)and(map[j,i]=0) then
begin inc(e);
edges[e].a:=i;edges[e].b:=j;edges[e].len:=xs;
map[i,j]:=1;map[j,i]:=1;
end;
end;
fori:=1 to n do p[i]:=i; //初始化并查集
randomize;
quicksort(1,e); //使用快速排序将边按权值从小到大排列
end;
function find(x:integer):longint; //并查集的Find,用来判断2个顶点是否属于一个连通分量
begin
ifx<>p[x] then p[x]:=find(p[x]);
find:=p[x]
end;
procedure union(a,b:longint); //如果不属于且权值最小则将2个顶点合并到一个连通分量
var
t :integer;
begin
a:=find(a);b:=find(b);
ifr[a]>r[b] then begin t:=a;a:=b;b:=t end;
ifr[a]=r[b] then inc(r[b]);
p[a]:=b;
end;
procedure kruskal; //主过程
var
en :longint; //en为当前边的编号
count :longint; //统计进行了几次合并。n-1次合并后就得到最小生成树
tot :longint; //统计最小生成树的边权总和
begin
count:=0;en:=0; tot:=0;
while count<n-1 do
begin
inc(en);
with edges[en] do
begin
if find(a)<>find(b) then
begin
union(a,b);
inc(tot,len);
inc(count);
end;
end;
end;
writeln(f2,tot)
end;
{===========main==========}
begin
init;
kruskal;
close(f1);close(f2);
end.