做了个对比.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一样了真不错.