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一样了真不错.