Kruskal vs Bor?vka

做了个对比.Bor?vka算法对于稠密图效果特别好.这两个都是求生成森林的算法.Prim+heap+tarjan过于难写不写了.

V=200,E=1000
Kruskal method
487504811
Time usage: 129 us
Bor(uc)uvka method
487504811
Time usage: 94 us
V=500,E=3000
Kruskal method
1068863143
Time usage: 431 us
Bor(uc)uvka method
1068863143
Time usage: 321 us
V=1000,E=10000
Kruskal method
1248132507
Time usage: 1626 us
Bor(uc)uvka method
1248132507
Time usage: 707 us
V=2000,E=50000
Kruskal method
1023451601
Time usage: 4444 us
Bor(uc)uvka method
1023451601
Time usage: 1781 us
V=5000,E=100000
Kruskal method
3177798955
Time usage: 8300 us
Bor(uc)uvka method
3177798955
Time usage: 3473 us
V=10000,E=300000
Kruskal method
4240792222
Time usage: 26751 us
Bor(uc)uvka method
4240792222
Time usage: 11332 us
V=10000,E=500000
Kruskal method
2548867302
Time usage: 45754 us
Bor(uc)uvka method
2548867302
Time usage: 18561 us
V=20000,E=1000000
Kruskal method
5166175346
Time usage: 92360 us
Bor(uc)uvka method
5166175346
Time usage: 38672 us
V=50000,E=1000000
Kruskal method
32391070642
Time usage: 96633 us
Bor(uc)uvka method
32391070642
Time usage: 54670 us
V=100000,E=1000000
Kruskal method
129350661440
Time usage: 101094 us
Bor(uc)uvka method
129350661440
Time usage: 79034 us
V=300000,E=2000000
Kruskal method
578989469565
Time usage: 229092 us
Bor(uc)uvka method
578989469565
Time usage: 208983 us
V=500000,E=6000000
Kruskal method
536707083899
Time usage: 689042 us
Bor(uc)uvka method
536707083899
Time usage: 654468 us
V=1000000,E=10000000
Kruskal method
1290266237257
Time usage: 1254349 us
Bor(uc)uvka method
1290266237257
Time usage: 1443208 us
V=5000000,E=50000000
Kruskal method
6456472043049
Time usage: 8274752 us
Bor(uc)uvka method
6456472043049
Time usage: 16565600 us
V=10000000,E=50000000
Kruskal method
25804619307783
Time usage: 10263962 us
Bor(uc)uvka method
25804619307783
Time usage: 18875336 us

这个Boruvka的写法不是最好的;但是链表动态删除的Boruvka会很长也就没有比较的意义了.

#define sizex 100000000
#include <cmath>
#include <cstdio>
#include <random>
#include <algorithm>
#include <malloc.h>
#include <sys/time.h>
using namespace std;
int *data,res;
long long mytic(){
	long long result = 0.0;
	struct timeval tv;
	gettimeofday( &tv, NULL );
	result = ((long long)tv.tv_sec)*1000000 + (long long)tv.tv_usec;
	return result;
}
#define dic1() disA(generator)
#define dic2() disB(generator)
struct edge{int a,b,w;};
bool cmp(edge a,edge b){
	return a.w<b.w;
}
#define foredge for(int i=0;i<gr.El;++i)
#define forvert2 for(int i=0;i<gr.N;++i)
#define eg gr.E[i]
struct graph{
	int N,El;
	edge E[50000000];
	void sorter(){
		sort(E,E+El,cmp);
	}
	void genData(int a,int b){
		N=a;
		El=b;
		mt19937 generator;
		uniform_int_distribution<int> disA(0,N-1);
		uniform_int_distribution<int> disB(0,21474836);
		for(int i=0;i<El;++i){
			E[i].a=dic1();
			while((E[i].b=dic1())==E[i].a);
			E[i].w=dic2();
		}
	}
} gr;
struct ds_set{
	int fa[10000000];
	void clear(){
		for(int i=0;i<gr.N;++i) fa[i]=-1;
	}
	int find(int p){return ~fa[p]?fa[p]=find(fa[p]):p;}
	inline int merge(int a,int b){return (a==b)?(-1):(fa[b]=a);}
} ds;
#define ffind(a) ds.find(a)
#define funion(a,b) ds.merge(a,b)
struct algo_Kruskal{
	long long run(){
		long long ans=0;
		gr.sorter();
		int a,b;
		foredge{
			a=ffind(eg.a),b=ffind(eg.b);
			ans+=~funion(a,b)?eg.w:0;
		}
		return ans;
	}
} Kruskal;
struct algo_Boruvka{
	struct v{
		int a,p;
	} vm[10000000];
	long long run(){
		long long ans=0;
		int a,b,c,w;
		while(1){
			c=0;
			forvert2 vm[i].a=100000000;
			foredge{
				w=eg.w,a=ffind(eg.a),b=ffind(eg.b);
				if(a==b) continue;
				++c;
				if(w<vm[a].a) vm[a]={w,i};
				if(w<vm[b].a) vm[b]={w,i};
			}
			if(!c) break;
			forvert2 if(vm[i].a!=100000000) {
				a=ffind(gr.E[vm[i].p].a);
				vm[i].p=ffind(gr.E[vm[i].p].b);
				ans+=(~funion(a,vm[i].p))?vm[i].a:0;
			}
		}
		return ans;
	}
} Boruvka;
FILE* loggar;
void testN(){
	long long i;
	printf("Kruskal method\n");
	fprintf(loggar,"Kruskal method\n");
	ds.clear();
	long long start=mytic();
	i=Kruskal.run();
	start=mytic()-start;
	printf("%lld\n",i);
	printf("Time usage: %lld us\n",start);
	fprintf(loggar,"%lld\n",i);
	fprintf(loggar,"Time usage: %lld us\n",start);
}
void testU(){
	long long i;
	printf("Bor(uc)uvka method\n");
	fprintf(loggar,"Bor(uc)uvka method\n");
	ds.clear();
	long long start=mytic();
	i=Boruvka.run();
	start=mytic()-start;
	printf("%lld\n",i);
	printf("Time usage: %lld us\n",start);
	fprintf(loggar,"%lld\n",i);
	fprintf(loggar,"Time usage: %lld us\n",start);
}
int as[15]={200 ,500 ,1000 ,2000 ,5000  ,10000 ,10000 ,20000  ,50000  ,100000 ,300000 ,500000 ,1000000 ,5000000 ,10000000};
int bs[15]={1000,3000,10000,50000,100000,300000,500000,1000000,1000000,1000000,2000000,6000000,10000000,50000000,50000000};
int main(){
	int a,b,c,i,j,k,l,m,n,N,U,P,UP;
	loggar=fopen("MSTTest.data","w");
	for(int i=0;i<15;++i){
		printf("%d %d\n",as[i],bs[i]);
		fprintf(loggar,"V=%d,E=%d\n",as[i],bs[i]);
		gr.genData(as[i],bs[i]);
		testN(),testU();
	}
	fclose(loggar);
	return 0;
}

过饱和稠密图上花样虐Kruskal

V=3000,E=50000000
Kruskal method
2305771
Time usage: 5808210 us
Bor(uc)uvka method
2305771
Time usage: 1270494 us
V=5000,E=50000000
Kruskal method
6381189
Time usage: 5789551 us
Bor(uc)uvka method
6381189
Time usage: 1274763 us
V=10000,E=50000000
Kruskal method
25291282
Time usage: 5834369 us
Bor(uc)uvka method
25291282
Time usage: 1654772 us

稀疏图大概比Kruskal慢一倍,花样虐Prim.

还有一个小花絮就是我弄错随机数生成范围Kruskal狂错不止.

Prim+pbdsheap还是有前途的,不过Boruvka完全够了.

两个长度加起来和不带堆的Prim一样了真不错.

时间: 2024-12-25 12:13:42

Kruskal vs Bor?vka的相关文章

Bor?vka 算法求 MST 最小生成树

基本思路:用定点数组记录每个子树的最近邻居.对于每一条边进行处理:如果这条边连成的两个顶点同属于一个集合,则不处理,否则检测这条边连接的两个子树,如果是连接这两个子树的最小边,则更新 (合并).时间复杂度平均 \(O(V+E)\),最坏 \(O((V+E)\log V)\). 下面是 Bor?vka 算法演示动图:(源:Wikimedia) 程序代码: struct node {int x, y, w; } edge[M]; int d[N]; // 各子树的最小连外边的权值 int e[N];

Codeforces.888G.Xor-MST(Bor?vka算法求MST 贪心 Trie)

题目链接 \(Description\) 有一张\(n\)个点的完全图,每个点的权值为\(a_i\),两个点之间的边权为\(a_i\ xor\ a_j\).求该图的最小生成树. \(n\leq2*10^5,0\leq ai<2^{30}\). \(Solution\) 代码好神啊. 依旧是从高到低考虑每一位.对于当前位i,如果所有点在这一位都为0或1,不需要管(任何边在这一位都为0). 否则可以把点分为两个集合,即i位为0和1的集合,这两个集合间必须存在一条边,且边权这一位只能为1. 考虑怎么高

【BZOJ 3551】[ONTAK2010] Peaks加强版 Kruskal重构树+树上倍增+主席树

这题真刺激...... I.关于Kruskal重构树,我只能开门了,不过补充一下那玩意还是一棵满二叉树.(看一下内容之前请先进门坐一坐) II.原来只是用树上倍增求Lca,但其实树上倍增是一种方法,Lca只是他的一种应用,他可以搞各种树上问题,树上倍增一般都会用到f数组. |||.我们跑出来dfs序就能在他的上面进行主席树了. IV.别忘了离散. V.他可能不连通,我一开始想到了,但是我觉得出题人可能会是好(S)人(B),但是...... #include <cstdio> #include

最小生成树求法 Prim + Kruskal

prim算法的思路 和dijkstra是一样的 每次选取一个最近的点 然后去向新的节点扩张 注意这里的扩张 不再是 以前求最短路时候的到新的节点的最短距离 而是因为要生成一棵树 所以是要连一根最短的连枝 所以关键部分修改一下 dist[u] = min(dist[u], e.cost) --->>e是连接 v 和 u的边 同样地 普同写法O(v^2) 用队列优化后O(E*logV) 1 #include <iostream> 2 #include <stdio.h> 3

HDU 1389 继续畅通工程【最小生成树,Prime算法+Kruskal算法】

继续畅通工程 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 21871    Accepted Submission(s): 9356 Problem Description 省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可).现得到城镇道路统计表,表中列

poj1861 最小生成树 prim &amp; kruskal

// poj1861 最小生成树 prim & kruskal // // 一个水题,为的只是回味一下模板,日后好有个照应不是 #include <cstdio> #include <algorithm> #include <cstring> #include <vector> #include <iostream> using namespace std; const int MAX_N = 1008; const int INF =

hdu 1875 畅通工程再续(kruskal算法计算最小生成树)

畅通工程再续 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 18411    Accepted Submission(s): 5769 Problem Description 相信大家都听说一个"百岛湖"的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现.现在政府决定大力发展百岛湖,发展首先

HDU2122 Ice_cream’s world III【Kruskal】

Ice_cream's world III Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 997    Accepted Submission(s): 321 Problem Description ice_cream's world becomes stronger and stronger; every road is built

最小生成树 Prim(普里姆)算法和Kruskal(克鲁斯特尔)算法

Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小.该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现:并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现:1959年,艾兹格·迪科斯彻再次发现了该算法.因此,在某些场