最小生成树模板

来源:互联网 发布:匹配声音软件是什么 编辑:程序博客网 时间:2024/05/19 13:07
prim算法(矩阵形式):

#define inf 0x3f3f3f3f
int prim(int n,int sta)//n表示有n个顶点,sta表从sta这个顶点出发生成最小生成树
{
    intmark[M],dis[M];
    int i,sum =0;    //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];
    }
    returnsum;      //返回边权总和
}

prim算法(边表形式):

struct Edge//frm为起点,to为终点,w为边权,nxt指向下一个顶点
{
   // int frm;
    intto,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];
    head[cu] = e++;
   //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为起点
{
    int sum =0;
   memset(dis,0x3f,sizeof(dis));
   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--)
    {
       int min = inf;
       for (i = 0;i < n;i ++)//找出当前边权最小的边
           if (!vis[i]&&dis[i] < min)
               flag = i,min = dis[i];
       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 ()
{
    e =0;                 //记得初始化
    memset(head,-1,sizeof(head));
    scanf ("%d%d %d",&a,&b,&w);
   addedge(a,b,w);
    .....
    .....
   prim(n,sta);
    return0;
}
Kruskal算法:
struct Edge
{
    intv1,v2,w;
}edge[M],tree[M];          //w为v1顶点到v2顶点的边权
/ *
int Find (int parent[],int u)//第1种写法
{
    int tmp =u;
    while(paren[tmp] != -1)
       tmp = parent[tmp];
    returntmp;
}
*/

int Find (int u)  //第2种写法
{
    if (u !=parent[u])
       parent[u] = Find(paren[u]);
    returnparent[u];
}
bool cmp (Edge a,Edge b)
{
    return a.w< b.w;
}
int Kruskal()//parent[]表示集合
{
    intparent[M];
    inti,j,sum,vf1,vf2;
   sort(edge,edge+E,cmp);

  //  memset(parent,-1,sizeof(parent));//对应第1种并查集的初始化

    for (i = 0;i< n;i++)           //对应第2种并查集的安始化
       parent[i] = i;

    sum = i = j= 0;
    while (i< E && j < N - 1)//生成的边数为N-1
    {
       vf1 = Find(parent,edge[i].v1);  //找这两个点的祖先
       vf2 = Find(parent,edge[i].v2);
       if (vf1 !=vf2)        //若两个点的祖先不同,说明不在同一集合
       {
           parent[vf2] = vf1;  //把vf2点加到vf1点的集合中
           tree[j++] = edge[i]; //把边加到tree[]数组中,这句题目没要求可忽略之
           sum +=edge[i].w;   //sum 加上其边权
       }
       i ++;
    }
    returnsum;
}