算法之路-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