模板整理: 图论---最小生成树


最小/大生成树是个非常厉害的知识点,
题目可以出得很巧,
记住它的最优子结构性质,并且很多时候性质有大用(例如货车运输)
稀疏图Kruskal,稠密图(有时候)Prim.
求最小生成树一般都是2种:
1.prim
O( N2 ),可以用堆优化到O( Nlog(N) ),
不是很常用,不过其实也很好写。
好吧也不能说不常用,我是指我用得比较少= =
毕竟C++一个sort就可以做Kruskal了。
还有啥啥fib堆优化prim的就随风远去吧。

//这是个O(n^2)的prim
//Map[i][j]表示i到j边的权值
//注意初始化vis(如果你要多次运行这个的话)
int Prim(){
    int ans=0;
    for (int i=1;i<=n;i++) dis[i]=Map[1][i];
    vis[1]=1;
    for (int i=1;i<n;i++){
        int Min=inf,mi=0;
        for (int j=1;j<=n;j++)
            if (!vis[j] && Min>dis[j]) Min=dis[j],mi=j;
        vis[mi]=1;
        ans=max(ans,Min);
        for (int j=1;j<=n;j++)
            if (dis[j]>Map[mi][j]) dis[j]=Map[mi][j];
    }
    return ans;
}


2.Kruskal
把边排序然后贪心。
好写而且一般都挺快的(除非边真的多)
还可以结合高级数据结构做些事体(=v= bzoj3669)

//Edge是输入的边,这些是准备部分
struct Edge{  
    int L,R,num;  
}E[M];  
bool cmp(Edge x,Edge y){  
    return x.num<y.num;  
}  
int getfa(int x){  
    if (fa[x]!=x) fa[x]=getfa(fa[x]);  
    return fa[x];  
}  //并查集
bool unn(int x,int y){  
    int t1=getfa(x),t2=getfa(y);  
    if (t1==t2) return 1;  
        else{  
            fa[t2]=t1;  
            return 0;  
        }   
}  //合并x和y,并且如果x和y已经一起返回1,不然返回0

//这是主程序里的内容,tot为边数,n为点数,E是Edge类型
    sort(E+1,E+1+tot,cmp);
    for (int i=0;i<=n;i++) fa[i]=i;
    int ans=0; //答案统计
    for (int i=1;i<=tot;i++){
        if (unn(E[i].L,E[i].R)) continue;
        ans+=E[i].num;
    }


还有个平面图最小生成树,BFS处理的,
不会考,那么模板先这样了,
主要是会去用,本质是dp(写法是贪心)

猜你喜欢

转载自blog.csdn.net/ThinFatty/article/details/78491329