码迷,mamicode.com
首页 > 其他好文 > 详细

最小生成树之 prim算法和kruskal算法(以 hdu 1863为例)

时间:2014-07-26 00:58:06      阅读:251      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   os   strong   io   for   

最小生成树的性质

MST性质:设G = (V,E)是连通带权图,U是V的真子集。如果(u,v)∈E,且u∈U,v∈V-U,且在所有这样的边中,

(u,v)的权c[u][v]最小,那么一定存在G的一棵最小生成树,(u,v)为其中一条边。

构造最小生成树,要解决以下两个问题:
(1).尽可能选取权值小的边,但不能构成回路(也就是环)。
(2).选取n-1条恰当的边以连接网的n个顶点。

Prim算法的思想:

设G = (V,E)是连通带权图,V = {1,2,…,n}。先任选一点(一般选第一个点),首先置S = {1},然后,只要S是V的真子集,就选取满足条件i ∈S,j ∈V-S,且c[i][j]最小的边,将顶点j添加到S中。这个过程一直进行到S = V时为止。在这个过程中选取到的所有边恰好构成G的一棵最小生成树。

 

Prim算法代码     

以 hdu 1863为例 (点击打开链接

bubuko.com,布布扣
#include<stdio.h>
#include<limits.h>
#include<string.h>
#define N 100
int n,m,map[N+5][N+5],v[N+5],low[N+5];
int prim()
{
    int i,j,pos,min,s=0;
    memset(v,0,sizeof(v));           //v[i]用来标记i是否已访问,先初始化为0,表示都未访问
    v[1]=1;                         //先任选一点作为第一个点
    pos=1;                          //pos用来标记当前选的点的下标
    for(i=2;i<=n;i++)
        low[i]=map[1][i];          //用low数组存已选点到其他点的权值
    for(i=1;i<n;i++){
        min=INT_MAX;
        for(j=1;j<=n;j++)                //求权值最小的边
            if(!v[j]&&low[j]<min){
                min=low[j];
                pos=j;                 
            }
        if(min==INT_MAX)    
            break;
        s+=min;            
        v[pos]=1;           
        for(j=1;j<=n;j++)                   //更新low数组    
            if(!v[j]&&map[pos][j]<low[j])
                low[j]=map[pos][j];
    }
    if(i!=n)
        s=-1;
    return s;
}
int main()
{
    int i,j,s,a,b,c;
    while(scanf("%d%d",&m,&n)!=EOF){          //m为道路数,n为村庄数
        if(m==0)
            break;
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
                map[i][j]=INT_MAX;             //先将map数组初始化为很大的值(int 最大值)
        for(i=1;i<=m;i++){
            scanf("%d%d%d",&a,&b,&c);
            map[a][b]=map[b][a]=c;             //map[a][b]存的从a到b的权值
        }
        s=prim();
        if(s==-1)
            printf("?\n");
        else
            printf("%d\n",s);
    }
    return 0;
}
View Code

 

Kruskal算法思想

给定无向连同带权图G = (V,E),V = {1,2,...,n}。

(1)首先将G的n个顶点看成n个孤立的连通分支。将所有的边按权从小大排序。

(2)从第一条边开始,依边权递增的顺序检查每一条边。并按照下述方法连接两个不同的连通分支:当查看到第k条边(v,w)时,如果端点v和w分别是当前两个不同的连通分支T1和T2的端点是,就用边(v,w)将T1和T2连接成一个连通分支,然后继续查看第k+1条边;如果端点v和w在当前的同一个连通分支中,就直接再查看k+1条边。这个过程一个进行到只剩下一个连通分支时为止。此时,已构成G的一棵最小生成树。

Kruskal算法代码:

以 hdu 1863为例 (点击打开链接

bubuko.com,布布扣
 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 int f[105],n,m;
 5 struct stu
 6 {
 7     int a,b,c;
 8 }t[5500];
 9 int cmp(struct stu x,struct stu y)
10 {
11     return x.c<y.c;
12 }
13 int find(int x)              //路径压缩,找父节点
14 {
15     if(x!=f[x])
16         f[x]=find(f[x]);
17     return f[x];
18 }
19 int krus()
20 {
21     int i,k=0,s=0,x,y;
22     for(i=1;i<=n;i++){
23         x=find(t[i].a);
24         y=find(t[i].b);
25         if(x!=y){              //最小生成树不能形成环,所以要判断它们的是否属于同一集合
26             s+=t[i].c;
27             k++;
28             if(k==m-1)      //<span style="font-family: KaiTi_GB2312;">最小生成树会形成m-1(顶点-1)条边,若已形成,则最小生成树已构成</span>
29                 break;
30             f[x]=y;          //将父节点更新
31         }
32     }
33     if(k!=m-1)
34         s=-1;
35     return s;
36 }
37 int main()
38 {
39     int i,s;
40     while(scanf("%d%d",&n,&m)!=EOF){
41         if(n==0)
42             break;
43         for(i=1;i<=n;i++)
44             scanf("%d%d%d",&t[i].a,&t[i].b,&t[i].c);
45         for(i=1;i<=m;i++)         //f[i]存的结点i的父亲,先将其父亲都初始化为其本身
46             f[i]=i;
47         sort(t+1,t+1+n,cmp);      //按权值从小到大排序
48         s=krus();
49         if(s==-1)
50             printf("?\n");
51         else
52             printf("%d\n",s);
53     }
54     return 0;
55 }
View Code

 

 

注:若顶点数为n,边为e

prim算法适合稠密图,其时间复杂度为O(n^2),其时间复杂度与边的数目无关,

kruskal算法的时间复杂度为O(eloge)跟边的数目有关,适合稀疏图。



最小生成树之 prim算法和kruskal算法(以 hdu 1863为例),布布扣,bubuko.com

最小生成树之 prim算法和kruskal算法(以 hdu 1863为例)

标签:style   blog   http   color   os   strong   io   for   

原文地址:http://www.cnblogs.com/happy-lcj/p/3855407.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!