最小生成树邻接表模板

来源:互联网 发布:黑客破解软件授权 编辑:程序博客网 时间:2024/06/18 16:28
/*我的经验是prim加了堆优化之后比kruskal快一点点点点点点。所以99%的时间都是用的kruskal*//*prim算法(矩阵形式):*/#include<stdio.h>#include<algorithm>#define M 6000*3  //双向边 所以要乘 切记#define inf 0x3f3f3f3fint e;//边数  //prim算法(边表形式):struct Edge//frm为起点,to为终点,w为边权,nxt指向下一个顶点{    int frm;    int to,w,nxt;}edge[M];int vis[M],head[M],dis[M];void addedge (int cu,int cv,int cw)//生成边的函数{    edge[e].frm = cu;    edge[e].to = cv;    edge[e].w = cw;    edge[e].nxt = head[cu];//前一个.frm=cu的edge编号,如果没有 head[cu]=-1;    head[cu] = e ++;//head[cu] 存最后一次存入的edge 编号    edge[e].frm = cv;    edge[e].to = cu;    edge[e].w = cw;    edge[e].nxt = head[cv];    head[cv] = e ++;}int prim(int n,int sta) //n为顶点数量,sta为起点{    if(e/2<n-1)return -1; //边不够 返回-1 表示不完全图    int sum = 0,i,flag;    for(i=0;i<n;i++)    {   dis[i]=inf;    }    memset(vis,0,sizeof(vis));    for (i = head[sta];i != -1;i = edge[i].nxt)//遍历与sta点相连的所有顶点    {        int v = edge[i].to;        dis[v] = edge[i].w;    }    vis[sta] = 1; //加入到最小生成树中    int m = n - 1;  //只生成n-1条边,所以循环n-1次    while (m --)    {if(n==0)return-1if(e/2<n-1)return -1;        int min = inf;        for (i = 0;i < n;i ++)/出当前边权最小的边{if (!vis[i]&&dis[i] < min)                flag = i,min = dis[i];}if(min==inf) //没找到可以用的边  代表图不完全 返回-1return -1;        sum += dis[flag];        vis[flag] = 1;//加入到最小生成树中        for (i = head[flag];i != -1;i = edge[i].nxt)//更新与flag顶点相连的点的dis        {                                           //            int v = edge[i].to;            if (edge[i].w < dis[v])                dis[v] = edge[i].w;        }    }    return sum; //返回边权总和}int main () {int a,b,w,n,i,j;while(scanf("%d",&n),n){memset (head,-1,sizeof(head));e = 0;                  //记得初始化for(i=0;i<n*(n-1)/2;i++){scanf ("%d%d%d",&a,&b,&w);a--,b--;addedge(a,b,w);}printf("%d\n",prim(n,1));//prim(int n,int sta) //n为顶点数量,sta为起点}return 0;}/*邻接矩阵int prim(int n,int sta)//n表示有n个顶点,sta表从sta这个顶点出发生成最小生成树{    int mark[M],dis[M],flag;    int i,sum = 0,j;     //sum是总的最小生成树边权值    for (i = 0;i < n;i ++) //初始化dis[i] 表从顶点sta到点i的权值    {        dis[i] = mat[sta][i];        mark[i] = 0;    }    mark[sta] = 1;           //sta 这个顶点加入最小生成树中    for (i = 1;i < n;i ++)   //循环n-1次,每次找出一条最小权值的边 n个点的图    {                        //只有n-1条边        int min = inf;       //inf 表无穷大        for (j = 0;j < n;j ++)/出当前未在最小生成树中边权最小的顶点            if (!mark[j] && dis[j] < min)                min = dis[j],flag = j;        mark[flag] = 1;         //把该顶点加入最小生成树中        sum += dis[flag];       //sum加上其边权值        for (j = 0;j < n;j ++)  //以falg为起点更新到各点是最小权值            if (dis[j] > mat[flag][j])                dis[j] = mat[flag][j];    }    return sum;       //返回边权总和}*/

0 0
原创粉丝点击