最小生成树

算法竞赛模板 最小生成树

ε祈祈猫儿з 提交于 2020-02-13 14:08:09
①克鲁斯卡尔算法(Kruskal) n 是顶点数, m 是边数; cnt 是已连的边数,如果已连的边数=总点数-1,即可跳出。 #include<bits/stdc++.h> #define MAX 1005 using namespace std; int p[MAX],n,m; struct edge{ int x,y,w; }a[MAX]; int find(int r) { if(p[r]!=r) p[r]=find(p[r]); return p[r]; } void join(int x,int y) { int fx=find(x),fy=find(y); if(fx!=fy) p[fx]=fy; } void init() { for(int i=0;i<=MAX;i++) p[i]=i; } bool cmp(edge a,edge b) { return a.w<b.w; } int kruskal() { sort(a,a+m,cmp); int cnt=0,cost=0,i; for(i=0;i<m;i++) { int fx=find(a[i].x),fy=find(a[i].y); if(fx!=fy) { p[fx]=fy; cost+=a[i].w; cnt++; } if(cnt==n-1)break; } return cost; } int

最小生成树(模板)

匆匆过客 提交于 2020-02-13 14:07:16
51nod1212最小生成树模板题: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1212 克鲁斯卡尔(加边法):先取最小的边,在判断是不是一个集合(不是舍去,是加上) 普里姆(加点法):先已经判断了不是一个集合,再从不是的集合中找出最小的边把点加入,最后更新(再取,再更新。。) 都是加到n-1条边停止(n个点最少由n-1条边连通),另外,Kruskal不用考虑重边(并查集自动取舍),Prim需要考虑重边(不考虑必错!) (关于去最小边,克鲁斯卡尔事先排序好按顺序取即可,所以是n*logn;普里姆每轮之后都要更新,所以每次取都循环找一次,所以是n*n,当然最后还可以优化这里就不说了) 克鲁斯卡尔 以边为重点进行各种操作,点不是重点,所以存图方式不重要很简单。(把边连接信息表示出来就行,结构体完美表示) 另外关于并查集,初学并查集推荐不用深度优化,只改变父节点就行更加好理解,而且时间也差不了多少 初级并查集 1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 #include <iomanip> 5 #include <cstdio> 6 #include <cstring> 7 using namespace std; 8

【模板】最小生成树

喜你入骨 提交于 2020-02-13 14:05:58
给定一个无向图,求其最小生成树 在无向图中,连通且不含环的图称为树。给定无向图 \(G=(V,E)\) ,连接 \(G\) 中所有点,且边集是 \(E\) 的子集称为 \(G\) 的生成树。 ( \(Spanning Tree\) )。 那么对于 \(G\) 的所有生成树,其中边权值最小的就是无向图 \(G\) 的最小生成树。 这里使用的是 \(Kruskal\) 。克鲁斯卡尔算法代码复杂度较低,的时间复杂度是以边数来决定的。 而(我还不会的) \(Prim\) 算法是以点为核心的。 核心 贪心+并查集……将边按权值从小到大排序,如果说第 \(i\) 条边的两个节点 \(u[i]\) 和 \(v[i]\) 不在【未完成生成树中的】同一个连通分量中,那么它一定属于最小生成树。 然后就将这两个点所在的连通分量合并,这条边加入生成树 正确性易证 #include <algorithm> #include <iostream> #include <cstdio> #include <cmath> using namespace std; #define MAXM 200005<<1 #define MAXN 5005 struct edge { int u,v,w; }e[MAXM]; bool cmp(const edge x,const edge y) { return x.w<y.w

最小生成树模板

空扰寡人 提交于 2020-02-13 14:01:33
prim算法适合稠密图,其时间复杂度为O(n^2),其时间复杂度与边得数目无关,而kruskal算法的时间复杂度为O(eloge)跟边的数目有关,适合稀疏图。 一、 普利姆算法(prim) 1 // 可以输出最短路中的边 2 #define inf 0x3f3f3f3f 3 int n,mindis; //n个顶点 4 int map[1000][1000]; // 边的权值 5 int vis[1000]; // 标记变量 1表示此下标的顶点已经加入生成树 6 int dis[1000]; // 出发点到该下标的权值 7 void prim() 8 { 9 int i,j,mindis = 0,min,pos; 10 for(i = 1; i <= n; i ++) 11 { 12 dis[i] = map[1][i]; 13 vis[i] = 1; 14 } 15 vis[1] = -1; // 起点已经加入生成树 16 for (i = 1; i < n; i ++) // 循环除起点外的其他顶点 17 { 18 min = inf; pos = -1; 19 for (j = 1; j <= n; j ++) // 寻找最小权值 20 { 21 if (vis[j] != -1 && dis[j] < min) 22 { 23 min = dis[j]; 24 pos =

最小生成树模板

安稳与你 提交于 2020-02-13 13:59:44
  prim算法: #include<bits/stdc++.h> using namespace std; //input by bxd #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define RI(n) scanf("%d",&(n)) #define RII(n,m) scanf("%d%d",&n,&m) #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k) #define RS(s) scanf("%s",s); #define LL long long #define REP(i,N) for(int i=0;i<(N);i++) #define CLR(A,v) memset(A,v,sizeof A) ////////////////////////////////// #define inf 900000r #define N 1000 int n,m; int ans; int mp[N][N]; int vis[N]; struct edge { int to;//to为通向的边 int v;//为权值 friend bool operator<(const edge& a,const edge& b) { return a.v>b.v; } }now; void prim

最小生成树模板

為{幸葍}努か 提交于 2020-02-13 13:55:40
Kruskal算法 伪代码 sort间接排序r[i]数组,找出权值最小的边 进行判断如果不是在一块的,那么答案加上权值两条边合并 模板 #include <bits/stdc++.h> using namespace std; int f[200010],r[200010]; int num[200010],to[200010],cost[200010]; int n,m; bool cmp(int a,int b) { return cost[a]<cost[b]; } int find(int k) { return f[k]==k?k:f[k]=find(f[k]); } int main() { cin>>n>>m; int ans=0,sum=0; for(int i=0;i<m;i++) cin>>num[i]>>to[i]>>cost[i]; for(int i=0;i<n;i++) f[i]=i; for(int i=0;i<m;i++) r[i]=i; sort(r,r+m,cmp); for(int i=0;i<m;i++) if(find(num[r[i]])!=find(to[r[i]])) { ans+=cost[r[i]]; f[find(num[r[i]])]=find(to[r[i]]); } cout<<ans; } 来源: https://www

最小生成树模板

元气小坏坏 提交于 2020-02-13 13:55:23
Prim算法,O(V^2),适用于稠密图。 1 const int N=1000; 2 const int INF=0x3f3f3f3f; 3 int a[N][N],p[N],low[N];///邻接矩阵 4 int prim(int n) 5 { 6 int i,j,ans=0,poi; 7 memset(p,0,sizeof(p)); 8 p[1]=1; 9 for(i=1;i<=n;i++) 10 low[i]=a[1][i]; 11 for(i=1;i<n;i++) ////n-1次操作 12 { 13 int mi=INF; 14 for(j=1;j<=n;j++) 15 { 16 if(!p[j]&&mi>low[j]) 17 { 18 mi=low[j]; 19 poi=j; 20 } 21 } 22 p[poi]=1; 23 ans+=mi; 24 for(j=1;j<=n;j++) 25 if(!p[j]) 26 low[j]=min(low[j],a[poi][j]); 27 } 28 return ans; 29 } Prim Kruskal,O(ElogE)。将边按权值从小到大排序,枚举每一条边,若该边的两端不在同一集合中,合并集合。直到找到n-1条边(n为点数)。判断是否在一个集合也可以用并查集做。 1 ////O(ElogE) 适用于稀疏图 2

最小生成树的Kruskal算法

自闭症网瘾萝莉.ら 提交于 2020-02-13 13:54:54
库鲁斯卡尔(Kruskal)算法是一种按照连通网中边的权值递增的顺序构造最小生成树的方法。Kruskal算法的基本思想是:假设连通网G=(V,E),令最小生成树的初始状态为只有n个顶点而无边的非连通图T=(V,{}),图中每个顶点自成一个连通分量。在E中选择权值最小的边,若该边依附的顶点落在T中不同的连通分量中,则将此边加入到T中;否则,舍去此边而选下一条权值最小的边;依次类推,直到T中所有顶点都在同一个连通分量上(此时含有n-1边)为止,这时的T就是一棵最小的生成树。 注意,初始时T的连通分量为顶点个数n,在每一次选取最小权值的边加入到T时一定要保证T的连通分量减1;也即选取最小权值边所连接的两个顶点必须位于不同的连接分量上,否则应舍去此边而再选取下一条最小权值的边。 概述 实现Kruskal算法的关键是如何判断所选取的边是否与生成树中已保留的边形成回路,这可通过判断边的两个顶点所在的连通分量的方法来解决.为此设置一个辅助数组vest(数组元素下标为0~n-1),它用于判断两个顶点集合(即两个连通分量),此时按其中的一个集合编号重新统一编号(即合并成一个连通分量)。因此,当两个顶点的集合(连通分量)编号不同时,则加入这两个顶点所构成的边到最小生成树中就一定不会形成回路,因为这两个顶点分属于不同的连通分量。 在实现Kruskal算法时,需要用一个数组E来存放图G中是所有边

Networking 最小生成树

时光总嘲笑我的痴心妄想 提交于 2020-02-13 11:34:49
题目: You are assigned to design network connections between certain points in a wide area. You are given a set of points in the area, and a set of possible routes for the cables that may connect pairs of points. For each possible route between two points, you are given the length of the cable that is needed to connect the points over that route. Note that there may exist many possible routes between two given points. It is assumed that the given possible routes connect (directly or indirectly) each two points in the area. Your task is to design the network for the area, so that there is a

学习笔记-动态树Link-Cut-Tree

落爺英雄遲暮 提交于 2020-02-11 03:29:56
--少年你有梦想吗? --少年你听说过安利吗? 安利一个集训队讲解: http://wenku.baidu.com/view/75906f160b4e767f5acfcedb 关于动态树问题,有多种方法。。LCT是其中比较常用的方法; LCT这种东西根本没用----by ShallWe ----你真的确定吗(charge) 我之前非常确定。 。。。。。。。。。 LCT的话,比较类似树链剖分,有类似轻重链的东东Preferred Path。不过链剖是用线段树维护,而LCT应用伸展树Splay维护。按深度维护。 动态树可以维护一个动态的森林,支持树的合并(两棵合并成一棵),分离(把某个点和它父亲点分开),动态LCA,树上的点权和边权维护、查询(单点或者树上的一条路径),换根。 具体的几个操作: Access操作: 大体上就是访问这个点。 是所有操作的基础,假设调用了过程ACCESS(v),那么从点v到根结点的路径就成为一条新的PreferredPath.如果路径上经过的某个结点u并不是它的父亲parent(u)的Pre-ferredChild,那么由于parent(u)的PreferredChild会变为u,原本包含parent(u)的PreferredPath将不再包含结点parent(u)及其之上的部分. 时间复杂度是均摊的logn证明详见开头的论文。。 Find_Root操作: