最小生成树-最小权值

两种方式:

1.kruskal:归并边   存储方式:邻接表      时间复杂度:O(eloge)    适用于:稀疏网

2.Prim算法:归并点   存储方式:矩阵    时间复杂度:O(n^2)       适用于:稠密网

(1)Kruskal

SL:将边按照从小到大排序,通过判断父节点是否相同,不同可归并,归并边次数n-1

/*
Kruskal:最小生成树
原理:归并边; 
*/
#include<iostream>
#include<algorithm>
using namespace std;
const int Max=10005; 
struct Node
{
	int u,v;
	int w;
}e[Max];
int fa[Max];
int cnt=0;
bool cmp(Node a,Node b)
{
	return a.w<b.w;
}
int init(int n)
{
	for(int i=1;i<=n;++i)
	fa[i]=i;
}
int getf(int x)
{
  return fa[x]==x?fa[x]:getf(fa[x]);	
} 
int merge(int u,int v)
{
	int tx=getf(u);
	int ty=getf(v);
	if(tx!=ty)
	{
		fa[ty]=tx;
		return 1;
	}
	return 0;
}
int Kruskal(int n,int  m)
{
	int sum=0;
	for(int i=1;i<=m;i++)
	{
		if(merge(e[i].u,e[i].v))
		{
		 cnt++;
		 sum+=e[i].w;	
	    }
	    if(cnt==n-1)
	    return sum;
	}
}
int main()
{
   int n,m;
   cout<<"输入顶点个数及边数:"<<endl;
   cin>>n>>m;
   init(n);
   cout<<"输入相关边信息:"<<endl;
   for(int i=1;i<=m;++i)
   {
   	cin>>e[i].u>>e[i].v>>e[i].w;
   }
   //对边排序
   sort(e+1,e+1+m,cmp);	
   cout<<"按权值从小到大排序后:"<<endl; 
   cout<<"-------------------"<<endl;
   for(int i=1;i<=m;i++)
   {
   	cout<<e[i].u<<" "<<e[i].v<<" "<<e[i].w<<" "<<endl;
   } 
	cout<<"------------------"<<endl; 
   int sum=Kruskal(n,m);
   cout<<"最小权值:"<<sum<<endl;
}
/*
input 
6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2
output 
19
*/

(2)Prim

 

/*
**最小生成树:
目的:获得最小权值 
**注意条件:
1.避圈法 
**方法:
1.Prim 
2.Kruscal 
*/
#include<iostream>
using namespace std;
const int Max=10005;
const int INF=99999999; 
int mp[Max][Max];
int path[Max];
int dis[Max],vis[Max]; 
int cnt=0;
int Prim(int n)
{
	cout<<"Starting"<<endl;
	int sum=0;
	for(int i=1;i<=n;i++)
	{
		dis[i]=mp[1][i];
	}
	int Min=INF,p;
	vis[1]=1;
	path[++cnt]=1;
	for(int i=1;i<n;++i)
	{
		Min=INF;
		for(int j=1;j<=n;j++)
		{
		  if(Min>dis[j]&&!vis[j])
		  {
		  	Min=dis[j];
		  	p=j;
		  }	
		}
		vis[p]=1;
		sum+=dis[p];
		path[++cnt]=p;
		for(int k=1;k<=n;k++)
		{
			if(dis[k]>mp[p][k])
			dis[k]=mp[p][k];
		}
	}
	return sum;
}
int main()
{
	int n,m,u,v,vl,c;
	cout<<"---------1. 使用已给样例-------------"<<endl;
	cout<<"---------2. 手动输入    -------------"<<endl;
	cin>>c;
	if(c==2)
	{
  	cout<<"输入顶点个数和弧数:"<<endl;
  	cin>>n>>m;
    
	}
	else
	{
		n=3,m=3;
	}
  	//初始化 
  	for(int i=1;i<=n;++i)
  	{
  	  for(int j=1;j<=n;j++)
  	  mp[i][j]=INF;
	} 
	if(c==2)
	{
	cout<<"相关联点的信息:"<<endl; 
	for(int i=0;i<m;++i)
	{
	 cin>>u>>v>>vl;
	 if(mp[u][v]>vl)
	 mp[u][v]=mp[v][u]=vl;//当两顶点之间的值有多个时。取最小的 
	} 
    }
    else
    {
	 mp[1][2]=mp[2][1]=1;
	 mp[2][3]=mp[3][2]=1;
	 mp[1][3]=mp[3][1]=4;	
	}
	int sum=Prim(n);
	cout<<"矩阵显示"<<endl;
	cout<<"------------------"<<endl;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;++j)
		cout<<mp[i][j]<<" ";
		cout<<endl;
	}
	cout<<"------------------"<<endl<<endl;
	cout<<"路径是:"<<endl; 
	for(int i=1;i<=cnt;++i)
	{
	cout<<path[i];
	if(i!=cnt)
	cout<<"-->";
    }
	cout<<endl;
	cout<<"最小权值:"<<endl;
	cout<<sum<<endl; 

//	cout<<"1到各个顶点的最短路径:"<<endl;
//	for(int i=2;i<=n;i++)
//	{
//		cout<<1<<"-->"<<i<<":"<<dis[i]<<endl;
//	}	 

}
/*
input 
6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2
output
19
*/

 

 

 

 

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值