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

来源:互联网 发布:淘宝突然搜不到了 编辑:程序博客网 时间:2024/06/11 01:27


最小/大生成树是个非常厉害的知识点,
题目可以出得很巧,
记住它的最优子结构性质,并且很多时候性质有大用(例如货车运输)
稀疏图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(写法是贪心)

原创粉丝点击