kruskal算法(使用并查集+贪心算法)

# include<iostream>
# include<cstring>
# define inf 0x3f3f3f3f
using namespace std;
const int maxn=100+5;
typedef struct node{
	int adj; //顶点之间的权重 
}node;
typedef struct graph{
	int vertex[maxn];
   node vertexs[maxn][maxn];//邻接矩阵 
    int vertexnum;
    int edgenum;
}graph;
bool vis[maxn][maxn];
int pre[maxn];
int minsum; 
int find(graph g,int i)  //寻找对应顶点的索引 
{
	for(int j=0;j<g.vertexnum;j++)
	    if(g.vertex[j]==i)
	      return j;
	return -1;
}
void init(graph &g)   //初始化图 
{
	cin>>g.vertexnum>>g.edgenum;
	for(int i=0;i<g.vertexnum;i++)
	  cin>>g.vertex[i];
	for(int i=0;i<g.vertexnum;i++)
	  for(int j=0;j<g.vertexnum;j++)
	      g.vertexs[i][j].adj=inf;
	for(int i=0;i<g.edgenum;i++)
	{
		int u,v,w;
		cin>>u>>v>>w;
	    int index_u=find(g,u);
		int index_v=find(g,v);
		if(index_u==-1||index_v==-1)
		  {
		  	  cout<<"不存在该节点"<<endl;
		  	 continue;
			} 
		g.vertexs[index_u][index_v].adj=w;
		g.vertexs[index_v][index_u].adj=w;   	
	  }
}
void makeset(int x)
{
	pre[x]=x;
}
int findset(int x)
{
	if(pre[x]==x)
	  return pre[x];
	else return pre[x]=findset(pre[x]);
}
bool link(int x,int y)  //如果不构成回路,就合并,并返回true,反之返回false 
{
	int xx=findset(x);
	int yy=findset(y);
	if(xx!=yy)
	{
		 pre[xx]=yy;
		 return true;
	   }  
   return false;
}

void mst_kruskal(graph g)
{
	
	for(int i=0;i<g.vertexnum;i++)
	   makeset(i);
	int index_v,index_u,cnt;
	cnt=0;   //边的初始个数 
	while(1)  
	{
		int min_edge=inf;
		if(cnt==g.vertexnum-1)//抽取完顶点数-1条边,结束循环 
		   break;
		for(int j=0;j<g.vertexnum;j++)
		{
		    for(int w=0;w<g.vertexnum;w++)
		    {
		    	if(j>w&&!vis[j][w]&&min_edge>g.vertexs[j][w].adj)  //只访问邻接矩阵的上三角,且访问没有访问过的 
		    	{
		    	   min_edge=g.vertexs[j][w].adj;
				   index_v=j;
				   index_u=w; 	
				   }
			}
		}
		 vis[index_v][index_u]=true;    //标记已访问 
	   if(link(index_v,index_u))   //判断是否构成回路,若构不成回路,再将顶点并入最小生成树的顶点集中 
	   {
	    cout<<"(v"<<g.vertex[index_u]<<",V"<<g.vertex[index_v]<<") ";
	   	cnt++;
	   	minsum+=min_edge;
			}	 
	}
	cout<<minsum<<endl;
}
int main()
{
	graph g;
	init(g);
	memset(vis,0,sizeof(vis));
	mst_kruskal(g);
	
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值