最小生成树算法
http://hi.baidu.com/mfs666/blog/item/3be684cb5508bffa53664f72.html
最小生成树是在图中构造一棵无根树,使所有点连同,且树的边权的和最小。一般是针对无向图的,如果是有向图的话,怎么处理?这个东西的应用一般就是顶以上的,如果用到应该很容易看出来。对于动态处理边的联机算法,貌似可以使用二叉堆来做卡鲁斯卡尔,或者是每次加入边时找出环,枚举来拆掉环中的边,貌似需要寻找环,用深搜?最近公共祖先?
program primandkrskr;
const
maxn=500;
maxp=3000;
type by=record //边表类型,用于克鲁斯卡尔
r,a,b:longint;u:boolean;//分别是边权,两端和使用标志
end;
var
b:array[0..maxp] of by;
m,s:array[0..maxn,0..maxn] of longint;
tr:array[0..maxn] of longint;
n,p,i,j,t,tt:longint;
function prim(x:longint):longint;//普利姆算法
var
dist,port:array[0..maxn] of longint;//离树的距离和接入树的点
i,j,mm,mt:longint;
begin
prim:=0;//初始化代价
for i:=1 to n do begin//初始化,将每个点离树的距离设为离初始点的距离(直接)(无法直接到达的是正无穷)
dist[i]:=m[x,i];
port[i]:=x;
end;
for j:=1 to n-1 do begin //加入N-1个点
mm:=maxlongint;//每次要初始化比较变量
for i:=1 to n do//枚举每个点
if (dist[i]<>0) and (dist[i]<mm) then begin//如果没有加入(离树的距离大于0),寻找离树最近的
mm:=dist[i];
mt:=i;
end;
inc(prim,mm);//代价增加这个距离
dist[mt]:=0;//加入树,离树距离变成0
for i:=1 to n do//松弛每个点
if m[mt,i]<dist[i] then begin//如果从新加入的点“直接去”某个点小于某个点到树的距离,则更新距离和接入点
dist[i]:=m[mt,i];
port[i]:=mt;
end;
end;
for i:=1 to n do
tr[i]:=port[i];
end;
function krskr(x:longint):longint;//克鲁斯卡尔算法,基于排序和并查集,时间复杂度约为O(eLoge),在稀疏图中很快
var
f:array[0..maxn] of longint;//并查集数组
i,j,c,ct:longint;
function find(x:longint):longint;//并查集查找
begin
if f[x]=x then begin
find:=x;
exit;
end;
find:=find(f[x]);
f[x]:=find;
end;
procedure com(x,y:longint);//并查集合并
var
fx,fy:longint;
begin
fx:=find(x);fy:=find(y);
if fx<>fy then
f[fx]:=fy;
end;
procedure qs(s,e:longint);//快速排序
var
i,j,m:longint;
t:by;
begin
i:=s;j:=e;m:=b[(i+j) shr 1].r;
repeat
while b[i].r<m do inc(i);
while b[j].r>m do dec(j);
if i<=j then begin
t:=b[i];
b[i]:=b[j];
b[j]:=t;
inc(i);dec(j);
end;
until i>j;
if i<e then qs(i,e);
if j>s then qs(s,j);
end;
begin
for i:=1 to n do//并查集初始化
f[i]:=i;
qs(1,p);//对边进行排序
ct:=0;//初始化已加入的边数
krskr:=0;//初始化代价
for i:=1 to p do begin//枚举排序好的边
if ct=n-1 then//如果已经完成生成树则退出
break;
if find(b[i].a)<>find(b[i].b) then begin//如果并查集不在同一集合中,说明加入边不会形成环
inc(ct);//增加边数
b[i].u:=true;//记录该边
com(b[i].a,b[i].b);//合并便两端的点所在集合
inc(krskr,b[i].r);//增加代价
end;
end;
end;
begin
readln(n,p);
for i:=1 to n do begin
for j:=1 to n do
m[i,j]:=maxlongint;
m[i,i]:=0;
end;
for i:=1 to p do begin
readln(t,tt,j);
m[t,tt]:=j;
m[tt,t]:=j;
b[i].r:=j;
b[i].a:=t;
b[i].b:=tt;
end;
writeln(prim(1));
writeln(krskr(1));
end.

浙公网安备 33010602011771号