算法之路-Kruskal and 欧拉降幂

Kruskal学习之路

    之前学习数据结构的时候,遇到最小生成树的算法,其中有一个就是很熟悉的prime算法。其次就是Kruskal。科普一下:Kruskal算法是一种用来查找最小生成树的算法,由Joseph Kruskal在1956年发表。用来解决同样问题的还有Prim算法和Boruvka算法等。三种算法都是贪心算法的应用。和Boruvka算法不同的地方是,Kruskal算法在图中存在相同权值的边时也有效。(From Baidu)
    今天做题的时候就发现以一个题算法就是最小生成树,然后也算是边做题边学习吧。
    先粘贴一下今天的题目吧。格式有点类似之前的套路?嘤嘤嘤
    首先对于我来说,算法的笔记参考文章
2、Kruskal算法流程
对于图G(V,E),以下是算法描述:
输入: 图G

输出: 图G的最小生成树

具体流程:

(1)将图G看做一个森林,每个顶点为一棵独立的树

(2)将所有的边加入集合S,即一开始S = E

(3)从S中拿出一条最短的边(u,v),如果(u,v)不在同一棵树内,则连接u,v合并这两棵树,同时将(u,v)加入生成树的边集E’

(4)重复(3)直到所有点属于同一棵树,边集E’就是一棵最小生成树

输入: 图G
输出: 图G的最小生成树
具体流程:
(1)将图G看做一个森林,每个顶点为一棵独立的树
(2)将所有的边加入集合S,即一开始S = E
(3)从S中拿出一条最短的边(u,v),如果(u,v)不在同一棵树内,则连接u,v合并这两棵树,同时将(u,v)加入生成树的边集E’
(4)重复(3)直到所有点属于同一棵树,边集E’就是一棵最小生成树

    首先题目就是挺直接的,没啥可以说的。
    先套用一下Kruskal别人的板子(非题解);
实践出真知,代码出奇迹

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,tot=0,k=0;//n端点总数,m边数,tot记录最终答案,k已经连接了多少边 
int fat[1000005];//记录集体老大 
struct node
{
   
	int from,to,dis;//结构体储存边 
}edge[200010];
bool cmp(const node &a,const node &b)//sort排序(当然你也可以快排) 
{
   
	return a.dis<b.dis;
}
int father(int x)//找集体老大,并查集的一部分 
{
   
	if(fat[x]!=x)
	return father(fat[x]);
	else return x;
}
void unionn(int x,int y)//加入团体,并查集的一部分 
{
   
	fat[father(y)]=father(x);
}
int main()
{
   
	scanf("%d%d",&n,&m);//输入点数,边数 
	for(int i=1;i<=m;i++)
	{
   
		scanf("%d%d%d",&edge[i].from,&edge[i].to,&edge[i].dis);//输入边的信息 
	}
	for(int i=1;i<=n;i++) fat[i]=i;//自己最开始就是自己的老大 (初始化) 
	sort(edge+1,edge+1+m,cmp);//按权值排序(kruskal的体现) 
	for(int i=1;i<=m;i++)//从小到大遍历 
	{
   
		if(k==n-1) break;//n个点需要n-1条边连接 
		if(father(edge[i].from)!=father(edge[i].to))//假如不在一个团体 
		{
   
			unionn(edge[i].from,edge[i].to);//加入 
			tot+=edge[i].dis;//记录边权 
			k++;//已连接边数+1 
		}
	}
	printf("%d",tot);
	return 0;
}

仿照上面的算法进行改进,把里面的算法写到函数里面(更加清晰易懂)
(某题库,找不见了)嘤嘤嘤

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
 
#define N 100005
int a[105][105];
struct graph{
   
  int x,y,wei;
}nodd[N];
int m,n,ufind[N];
 
int cmp(graph a1,graph a2){
   
  return a1.wei<a2.wei;
}
int find(int x){
   
  return ufind[x]==x? x : ufind[x]=find(ufind[x]);
}
int Kruskal(int a,int b){
   
	int ans=0;
	int i,j;
	for(i=1;i<=n;i++) ufind[i]=i;
	sort(nodd,nodd+m,cmp);
	ufind[a]=b;
	for(i=0;i<m;i++){
   
	  int x=find(nodd[i].x);  int y=find(nodd[i].y);
	  if(x!=y){
   
	    ans+=nodd[i].wei;
	    ufind[x]=y;
	  }
	}
	return ans;
}
 
int main(){
   
  int x
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值