图论之最小生成树

来源:互联网 发布:php程序员需要学什么 编辑:程序博客网 时间:2024/06/05 21:09

1:Kruskal(克鲁斯卡尔)

      克鲁斯卡尔算法是在剩下的所有未选取的边中,找最小边,如果和已选取的边构成回路,则放弃,选取次小边。他可以用并查集进行优化。

         克鲁斯卡其尔算法的时间复杂度为O(eloge)(e为网中边的数目),因此它相对于普里姆算法而言,适合于求边稀疏的网的最小生成树。

var        father:array[1..1000]of longint;        s:array[0..3] of longint;        a:array[0..500000,0..3] of longint;        i,ans,n,m:longint;procedure q(l,r:longint);var        i,j,x,mid:longint;begin        i:=l;        j:=r;        mid:=a[(l+r) shr 1,3];        while i<=j do        begin                while a[i,3]<mid do inc(i);                while a[j,3]>mid do dec(j);                if i<=j then                begin                        s:=a[i];                        a[i]:=a[j];                        a[j]:=s;                        inc(i);                        dec(j);                end;        end;        if l<j then q(l,j);        if i<r then q(i,r);end;function getfather(x:longint):longint;begin        if father[x]=0 then exit(x);        father[x]:=getfather(father[x]);        exit(father[x]);end;procedure he(x,y:longint);var        xx,yy:longint;begin        xx:=getfather(x);        yy:=getfather(y);        if xx<>yy then                father[xx]:=yy;end;begin        readln(n,m);        for i:=1 to m do                readln(a[i,1],a[i,2],a[i,3]);        q(1,m);        for i:=1 to m do                if getfather(a[i,1])<>getfather(a[i,2]) then                begin                        he(a[i,1],a[i,2]);                        ans:=ans+a[i,3];                end;        writeln(ans);end.
2:Prim(普里姆)

     

假设V是图中顶点的集合,E是图中边的集合,TE为最小生成树中的边的集合,则prim算法通过以下步骤可以得到最小生成树:1:初始化:U={u 0},TE={f}。此步骤设立一个只有结点u 0的结点集U和一个空的边集TE作为最小生成树的初始形态,在随后的算法执行中,这个形态会不断的发生变化,直到得到最小生成树为止。2:在所有u∈U,v∈V-U的边(u,v)∈E中,找一条权最小的边(u 0,v 0),将此边加进集合TE中,并将此边的非U中顶点加入U中。此步骤的功能是在边集E中找一条边,要求这条边满足以下条件:首先边的两个顶点要分别在顶点集合U和V-U中,其次边的权要最小。找到这条边以后,把这条边放到边集TE中,并把这条边上不在U中的那个顶点加入到U中。这一步骤在算法中应执行多次,每执行一次,集合TE和U都将发生变化,分别增加一条边和一个顶点,因此,TE和U是两个动态的集合,这一点在理解算法时要密切注意。3:如果U=V,则算法结束;否则重复步骤2。可以把本步骤看成循环终止条件。我们可以算出当U=V时,步骤2共执行了n-1次(设n为图中顶点的数目),TE中也增加了n-1条边,这n-1条边就是需要求出的最小生成树的边。
uses math;var        n,m,i,x,y,c,j,k,minn,sum:longint;        q:array [1..1000,1..1000]of longint;        bz:array [1..1000]of boolean;        d:array [1..1000]of longint;begin        readln(n,m);        for i:=1 to n do        begin                for j:=1 to n do                q[i,j]:=maxlongint div 10;        end;        for i:=1 to m do        begin                readln(x,y,c);                q[x,y]:=min(q[x,y],c);                q[y,x]:=min(q[y,x],c);        end;        for i:=1 to n do                d[i]:=q[i,1];        bz[1]:=true;        for i:=1 to n-1 do        begin                minn:=maxlongint;                for j:=1 to n do                begin                        if (minn>d[j])and(not bz[j]) then                        begin                                minn:=d[j];                                k:=j;                        end;                end;                bz[k]:=true;                sum:=sum+minn;                for j:=1 to n do                        d[j]:=min(q[k,j],d[j]);        end;        writeln(sum);end.

0 0
原创粉丝点击