最小生成树总结

原创 2017年07月27日 10:53:48

最小生成树

算法: Prim算法和Kruskal算法

prim算法:

1).输入:一个加权连通图,其中顶点集合为V,边集合为E;

2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;

3).重复下列操作,直到Vnew = V:

a.在集合E中选取权值最小的边

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 110
int map[MAXN][MAXN], lowcost[MAXN];
bool visit[MAXN];
int nodenum, sum;

void prim()
{
    int temp, k;
    sum = 0;
    memset(visit, false, sizeof(visit)); //初始化visit
    visit[1] = true;
    for(int i = 1; i <= nodenum; ++i) //初始化lowcost[i]
        lowcost[i] = map[1][i];
    for(int i = 1; i <= nodenum; ++i)//找生成树集合点集相连最小权值的边
    {
        temp = INF;
        for(int j = 1; j <= nodenum; ++j)
            if(!visit[j] && temp > lowcost[j])
                temp = lowcost[k = j];
        if(temp == INF) break;
        visit[k] = true; //加入最小生成树集合
        sum += temp;//记录权值之和
        for(int j = 1; j <= nodenum; ++j) //更新lowcost数组
            if(!visit[j] && lowcost[j] > map[k][j])
                lowcost[j] = map[k][j];
    }
}

int main()
{
    int a, b, cost, edgenum;
    while(scanf("%d", &nodenum) && nodenum)
    {
        memset(map, INF, sizeof(map));
        edgenum = nodenum * (nodenum - 1) / 2;
        for(int i = 1; i <= edgenum; ++i) //输入边的信息
        {
            scanf("%d%d%d", &a, &b, &cost);
            if(cost < map[a][b])
                map[a][b] = map[b][a] = cost;
        }
        prim();
        printf("%d\n", sum); //最小生成树权值之和
    }
    return 0;
}

练习题目:http://acm.hdu.edu.cn/showproblem.php?pid=1863

Kruskal算法:

1).记Graph中有v个顶点,e个边

2).新建图Graphnew,Graphnew中拥有原图中相同的e个顶点,但没有边

3).将原图Graph中所有e个边按权值从小到大排序

4).循环:从权值最小的边开始遍历每条边 直至图Graph中所有的节点都在同一个连通分量中
if 这条边连接的两个节点于图Graphnew中不在同一个连通分量中
添加这条边到图Graphnew中

详见博客:http://blog.csdn.net/lminy/article/details/50453675

代码实现:

自己习惯代码:

#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <queue>
#include <string>
#include <cstring>

using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
int pre[3000+10];
int n,m;
struct node
{
    int u,v,w;
}p[3000+10];
bool cmp(node x,node y)
{
    return x.w<y.w;
}
int Find(int x)
{
    if(pre[x]==x)
        return x;
    return pre[x]=Find(pre[x]);
}
void zuixiaoshu()
{
    for(int i=1;i<000+10;i++)
        pre[i]=i;
    int sum=0,num=0;
    int flag=0;
    for(int i=1;i<=m;i++)
    {
        int x=Find(p[i].u);
        int y=Find(p[i].v);
        if(x!=y)//判断能不能不形成环
        {
            sum+=p[i].w;
            pre[x]=y;
            num++;
        }
        if(num==n-1)
        {
            flag=1;
            break;
        }
    }
    if(flag==0||m<n-1)
        cout<<-1<<endl;
    else
    cout<<sum<<endl;
}
int main()
{
    //int n,m;
    cin>>n>>m;//n个点,m条边
    for(int i=1;i<=m;i++)
    {
        //int a,b,c;
        cin>>p[i].u>>p[i].v>>p[i].w;
    }
    sort(p+1,p+1+m,cmp);//给边排序
    zuixiaoshu();
    return 0;
}

网上代码:

typedef struct          
{        
    char vertex[VertexNum];                                //顶点表         
    int edges[VertexNum][VertexNum];                       //邻接矩阵,可看做边表         
    int n,e;                                               //图中当前的顶点数和边数         
}MGraph; 

typedef struct node  
{  
    int u;                                                 //边的起始顶点   
    int v;                                                 //边的终止顶点   
    int w;                                                 //边的权值   
}Edge; 

void kruskal(MGraph G)  
{  
    int i,j,u1,v1,sn1,sn2,k;  
    int vset[VertexNum];                                    //辅助数组,判定两个顶点是否连通   
    int E[EdgeNum];                                         //存放所有的边   
    k=0;                                                    //E数组的下标从0开始   
    for (i=0;i<G.n;i++)  
    {  
        for (j=0;j<G.n;j++)  
        {  
            if (G.edges[i][j]!=0 && G.edges[i][j]!=INF)  
            {  
                E[k].u=i;  
                E[k].v=j;  
                E[k].w=G.edges[i][j];  
                k++;  
            }  
        }  
    }     
    heapsort(E,k,sizeof(E[0]));                            //堆排序,按权值从小到大排列       
    for (i=0;i<G.n;i++)                                    //初始化辅助数组   
    {  
        vset[i]=i;  
    }  
    k=1;                                                   //生成的边数,最后要刚好为总边数   
    j=0;                                                   //E中的下标   
    while (k<G.n)  
    {   
        sn1=vset[E[j].u];  
        sn2=vset[E[j].v];                                  //得到两顶点属于的集合编号   
        if (sn1!=sn2)                                      //不在同一集合编号内的话,把边加入最小生成树   
        {
            printf("%d ---> %d, %d",E[j].u,E[j].v,E[j].w);       
            k++;  
            for (i=0;i<G.n;i++)  
            {  
                if (vset[i]==sn2)  
                {  
                    vset[i]=sn1;  
                }  
            }             
        }  
        j++;  
    }  
}  
版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

最小生成树总结(prim、并查集和kruskal) C++实现

摘要: 本文按照如下顺序进行: 1.介绍最小生成树的概念; 2.介绍prim算法的思想,以及C++实现; 3.介绍并查集概念,给出C++并查集的代码实现(因为kruskal算法必须用到并查集,所以在这...

图论--最小生成树总结(Prim&&Kruskal)

今天才写了prim的堆优化,发现kruskal居然比prim跑得快。。。回归正题: 以下是我个人对最小生成树各种算法的理解,以及我的代码。 以下我将点数称为n,边数称为m;Prim 算法过程(来...

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

图的最小生成树kruskal算法总结

kruskal算法的思想 假如N={V,{E}}是连通网,那么最小生成树的初始状态是由N个顶点自成连通分量构成的一片森林。在E中选择权值最小的边,当该边对应的两个顶点在不同分量时,则将该边加入到最小生...

最小生成树问题学习总结

//最小生成树之kruskal算法 #include #include using namespace std; struct linknode { int vex1,vex2; int we...

图的最小生成树prim算法总结

昨天刚刚把prim算法复习了一遍,现在把将自己的理解与总结写出来分享下,prim算法的思想通俗的讲就是:将连通网N={V,E}的顶点分为最小生成树集合U与非最小生成树集合V-U,然后从U中的顶点到V-...

算法总结之最小生成树

最小生成树的作用: 有很多点,点点之间有很多边,边有边权,我们要选择一些边,将所有点互相联通,构成一颗树,即为最小生成树 模板题:http://codevs.cn/problem/1231/ 算...

kruscal算法求最小生成树总结

生成树指无向图中包含图的所有节点,边集为原图子集的图; 最小生成树指权值最小的生成树,对于包含n个节点的无向图来说,它的最小生成树包含n-1条边。 kruskal算法求解最小生成树的基本步...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)