最小生成树模板

prim算法(矩阵形式):

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

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];
      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);
      return 0;
}
Kruskal算法:
struct Edge
{
      int v1,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];
      return tmp;
}
*/

int Find (int u)  //第2种写法
{
      if (u != parent[u])
              parent[u] = Find(paren[u]);
      return parent[u];
}
bool cmp (Edge a,Edge b)
{
      return a.w < b.w;
}
int Kruskal()//parent[]表示集合
{
      int parent[M];
      int i,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 ++;
      }
      return sum;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值