用三元组实现最小生成树

本文详细介绍了克鲁斯卡尔算法和普里姆算法的实现代码,这两种算法主要用于寻找加权图中的最小生成树,是图论和网络优化中的重要概念。通过具体的代码示例,展示了如何在C++环境中使用这两种算法来解决实际问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

克鲁斯卡尔&普里姆算法都在代码之中

#include<iostream>
#include<stdlib.h>
#define False 0
#define True 1
using namespace std;
typedef struct
{
 int pointvertexmyself_i;/*pointvertexmyself_i 这个顶点是和本顶点向连接的顶点*/
 int lowcost;/*记录pointvertexmyself_i 和 本顶点的边的权值*/ 
}Closedge;
Closedge closedge[100];/*全局变量用来记录V-U中边的权值*/ 
typedef struct/*定义三元组*/ 
{
 int startvertex;/*开始顶点*/ 
 int endvertex;/*结束顶点*/ 
 int adjacent;/*权值*/ 
}Triple; 
typedef struct/*定义图的结构体*/ 
{
 Triple triple[10000]; 
 int vertexnumber;
 int count;
}Graph;
int Miniclosedge(Graph G)/*求V-U中权值最小的边*/ 
{
 int cost=999999,u=1;
 for(int i=1;i<=G.vertexnumber;i++)/*进行循环比较得到最小权值变的下边u*/ 
 {
  if(closedge[i].lowcost<cost&&closedge[i].lowcost!=0)
  {
   u=i;
   cost=closedge[i].lowcost;
  }
 }
 return u;
}
int MiniSpanTreePrim(Graph G,int u)/*普里姆算法*/ 
{
 int sum=0;/*记录最小生成树的权值的和*/ 
 int t;
 for(int i=1;i<=G.vertexnumber;i++)/*初始化closedge*/ 
 {
  closedge[i].pointvertexmyself_i=u;
  closedge[i].lowcost=999999;
 }
 closedge[u].lowcost=0;
 for(int j=1;j<=G.count;j++)/*将所知道的变得权值赋给closedge
 因为本体是用无向图所以要进行两次:一次是“去 ”一次是“回 ”*/ 
  if(G.triple[j].startvertex==u)
  {
  closedge[G.triple[j].endvertex].pointvertexmyself_i=u;
  closedge[G.triple[j].endvertex].lowcost=G.triple[j].adjacent;
     }
     else if(G.triple[j].endvertex==u)
     {
     closedge[G.triple[j].startvertex].pointvertexmyself_i=u;
  closedge[G.triple[j].startvertex].lowcost=G.triple[j].adjacent;
  }
  else;
 for(int k=1;k<=G.vertexnumber-1;k++)/*得到最小生成树的n-1条边*/ 
 {
  t=Miniclosedge(G);/*得到最小权值边在closedge中的下标t*/ 
  u=closedge[t].pointvertexmyself_i;/*得到相连的顶点*/ 
  sum+=closedge[t].lowcost;/*将边的值加入sum*/ 
  closedge[t].lowcost=0;
  for(int i=1;i<=G.count;i++)/*更新closedge数组也要“有去有回 ”*/ 
  {
   if(G.triple[i].startvertex==t&&G.triple[i].adjacent<closedge[G.triple[i].endvertex].lowcost)
   {
     closedge[G.triple[i].endvertex].lowcost=G.triple[i].adjacent;
     closedge[G.triple[i].endvertex].pointvertexmyself_i=t;
   }
   else if(G.triple[i].endvertex==t&&G.triple[i].adjacent<closedge[G.triple[i].startvertex].lowcost)
   {
     closedge[G.triple[i].startvertex].lowcost=G.triple[i].adjacent;
     closedge[G.triple[i].startvertex].pointvertexmyself_i=t;
   }
  }
 }
 return sum;
}
int GetminiEdge(Graph G,int *vest)/*得到权值最小的边 因为不能形成环 所以有vest数组  vest数组是记录哪些点已经在集合U中当
U=V是vest中的数据全部为1 即: 所有点都已经背访问过了且在集合U中*/ 
{
 int k;
 for(int i=1;i<=G.count;i++)
 {/*确保两个点在不同的集合中 因为如果在同一个集合中会构成环或者不能连通*/ 
  if((vest[G.triple[i].startvertex]==0&&vest[G.triple[i].endvertex]==1)||(vest[G.triple[i].startvertex]==1&&vest[G.triple[i].endvertex]==0))
  {
   k=i;
   vest[G.triple[i].startvertex]=1;
   vest[G.triple[i].endvertex]=1;
   break;
  }
 }
 return k;/*因为G已经按边的权值排序了 因此K就是下一个最小的边在G.triple的下标值*/ 
}
int MinniSpanKuscal(Graph G)/*克鲁斯卡尔算法*/ 
{
 int *vest,sum=0;/*vest数组的作用已经在上面说明 sum的作用也同上*/ 
 vest=(int *)malloc(sizeof(int)*G.vertexnumber+1);/*动态申请空间*/ 
 for(int i=0;i<=G.vertexnumber;i++)
 vest[i]=0;/*因为所有的顶点都没有访问所以都赋值为0*/ 
 for(int i=1;i<=G.count;i++)/*对G.triple按边的权值进行排序(从小到大排序)*/ 
    for(int j=i;j<=G.count;j++)
    {
         if(G.triple[i].adjacent>G.triple[j].adjacent)
         {
          int a,b,c;/*交换信息*/ 
          a=G.triple[i].adjacent;b=G.triple[i].endvertex;c=G.triple[i].startvertex;
          G.triple[i].adjacent=G.triple[j].adjacent;
          G.triple[i].endvertex=G.triple[j].endvertex;
          G.triple[i].startvertex=G.triple[j].startvertex;
          G.triple[j].adjacent=a;G.triple[j].endvertex=b;G.triple[j].startvertex=c;
   }
    }
 vest[G.triple[1].startvertex]=1;/*第一条边是最小的 因此访问最小边的顶点*/ 
 vest[G.triple[1].endvertex]=1;
 sum+=G.triple[1].adjacent;
 for(int i=1;i<G.vertexnumber-1;i++)/*得到剩下的n-2条边*/ 
 {
  int t=GetminiEdge(G,vest);
  sum+=G.triple[t].adjacent;
 }
 free(vest);
 return sum;
}
int main()
{
 Graph G;/*创建一个图*/
 cin>>G.vertexnumber>>G.count;
 for(int i=1;i<=G.count;i++)/*输入边的信息*/ 
 {
  cin>>G.triple[i].startvertex;
  cin>>G.triple[i].endvertex;
  cin>>G.triple[i].adjacent;
 }
 int u=1,minisum;
 minisum=MiniSpanTreePrim(G,u);/*普里姆算法*/ 
 cout<<minisum<<endl;
 minisum=MinniSpanKuscal(G);/*克鲁斯卡尔算法*/ 
 cout<<minisum;
 return 0; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值