最小生成树 Kruskal和Prim算法

算法过程:

  • 1.将图中所有的边按照权值进行排序。

  • 2.将图中的每一条边进行遍历,找出权值最小的边(注意:不能与已经加入到最小生成树集合的边构成环),如果符合要求,则把该边加入到最小生成树的集合中。

  • 3.重复步骤2,添加一个计数器,直到边的数量为n-1的时候跳出循环,算法结束。

    #include <bits/stdc++.h>
    #define maxn 1005
    using namespace std;
    int pre[maxn];  //定义并查集数组
    int sum ; //最小权值和
    int _cout;
    struct  edge    //用结构体定义边,包括两个点和权值
    {
       int u;
       int v;
       int w;
    };
    edge e[maxn];  //定义边的个数
    //并查集代码
    int Find(int x)
    {
       int r =x;
       while(pre[r] != r)
             r = pre[r];
    
       int i=x,j;
       while(i != r)
       {
             j =pre[i];
             pre[i] = r;
             i = j;
       }
       return r;
    }
    int join(int x,int y)
    {
         int fx = Find(x);
         int fy = Find(y);
         if(fx != fy)
         {
              pre[fx] = fy;
              return 1;
         }
         return 0;
    }
    bool cmp(edge a, edge b)
    {
          return a.w<b.w;   //按照从小到大的顺序进行排列
    }
    int main()
    {
       int n,m;//n表示结点的个数,m表示给出的信息量(包含每一条边(u,v)的权值)
       while(scanf("%d %d",&n,&m) == 2)
       {
             sum = 0;
             _cout = 0;
             memset(e,0,sizeof(e));
             memset(pre,0,sizeof(pre));
             for(int i=1;i<=m;i++)
                  scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w);
              sort(e+1,e+m+1,cmp); //sort函数是左闭右开
              for(int i=1;i<=n;i++)
                    pre[i] = i;  // 初始化并查集数组
              for(int i=1;i<=m;i++) //对每一条边进行处理
              {
                     if(join(e[i].u , e[i].v)){
                           _cout ++ ; //每次成功合并两个点,就会生成一条边,统计边的数量
                           sum += e[i].w;
                     }
                     if(_cout == n-1)
                          break;
              }
              printf("%d\n",sum);
       }
       return 0;
    }

    Prim算法:

    此算法可以称为“加点法”,每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。
    Prim算法从任意一个顶点开始,每次选择一个与当前顶点集最近的一个顶点,并将两顶点之间的边加入到树中。Prim算法在找当前最近顶点时使用到了贪心算法

    #include <bits/stdc++.h>
    #define MAX 0x3f3f3f3f
    using namespace std;
    int logo[1010];//用0和1来表示是否被选择过
    int map1[1010][1010];
    int dis[1010];//记录任意一点到这一点的最近的距离
    int n,m;
    int prim()
    {
      int i,j,now;
      int sum=0;
      for(i=1;i<=n;i++)//初始化
      {
          dis[i]=MAX;
          logo[i]=0;
      }
      for(i=1;i<=n;i++)
      {
          dis[i]=map1[1][i];
      }
      dis[1]=0;
      logo[1]=1;
      for(i=1;i<n;i++)//循环查找
      {
          now=MAX;
          int min1=MAX;
          for(j=1;j<=n;j++)
          {
              if(logo[j]==0&&dis[j]<min1)
              {
                  now=j;
                  min1=dis[j];
              }
          }
          if(now==MAX)//防止不成图
          {
              break;
          }
          logo[now]=1;
          sum=sum+min1;
          for(j=1;j<=n;j++)//填入新点后更新最小距离,到顶点集的距离
          {
              if(logo[j]==0&&dis[j]>map1[now][j])
              {
                  dis[j]=map1[now][j];
              }
          }
      }
      if(i<n)
      {
          printf("?\n");
      }
      else
      {
          printf("%d\n",sum);
      }
    }
    int main()
    {
      while(scanf("%d%d",&m,&n)!=EOF)//n是点数
      {
          if(m==0)
          {
              break;
          }
          memset(map1,0x3f3f3f3f,sizeof(map1));//map是邻接矩阵储存图的信息
          for(int i=0;i<m;i++)
          {
              int a,b,c;
              scanf("%d%d%d",&a,&b,&c);
              if(c<map1[a][b])///防止出现重边
              {
                  map1[a][b]=map1[b][a]=c;
              }
          }
          prim();
      }
      return 0;
    }
    
全部评论

相关推荐

jack_miller:我给我们导员说我不在这里转正,可能没三方签了。导员说没事学校催的时候帮我想办法应付一下
点赞 评论 收藏
分享
点赞 1 评论
分享
牛客网
牛客企业服务