D08【模板】最小生成树 Kruskal 算法
D08 最小生成树 Kruskal 算法_哔哩哔哩_bilibili
Kruskal 算法 是个贪心算法,基本思想是从小到大加入边
维护一堆 集合,查询两个元素是否属于同一集合,合并两个集合
查询两点是否连通和连接两点 可以使用并查集维护
排序 𝑂(𝑚log𝑚) ,并查集 𝑂(𝑚𝛼(𝑚,𝑛)) ,时间复杂度为 𝑂(𝑚log𝑚)
P3366 【模板】最小生成树 - 洛谷 P1195 口袋的天空 - 洛谷
求最小生成树的边权和。
// Kruskal算法 O(mlogm) #include<bits/stdc++.h> using namespace std; const int N=200010; int n,m; int fa[N],ans,tot; pair<int,pair<int,int> >e[N]; //边集 int find(int u){ //并查集的找根 return fa[u]==u?u:fa[u]=find(fa[u]); } void kruskal(){ for(int i=1;i<=n;i++) fa[i]=i; sort(e+1,e+1+m); //排序 for(int i=1;i<=m;i++){ int x=find(e[i].second.first),y=find(e[i].second.second); if(x!=y){ fa[x]=y; ans+=e[i].first; if(++tot==n-1) break; } } if(tot==n-1) printf("%d\n",ans); else puts("orz"); } int main(){ cin>>n>>m; for(int i=1,u,v,w;i<=m;i++){ cin>>u>>v>>w; e[i]={w,{u,v}}; } kruskal(); }
P1546 [USACO3.1] 最短网络 Agri-Net - 洛谷
求最小生成树的边权和。
// 最小生成树 Kruskal算法 O(MlogM) #include<bits/stdc++.h> using namespace std; const int N=110,M=10010; int n,m,tot,ans,fa[N]; pair<int,pair<int,int> >e[M]; //边集 int find(int u){ //并查集的找根 return fa[u]==u?u:fa[u]=find(fa[u]); } void kruskal(){ sort(e+1,e+m+1); //排序 for(int i=1; i<=n; i++) fa[i]=i; for(int i=1; i<=m; i++){ int x=find(e[i].second.first),y=find(e[i].second.second); if(x!=y){ fa[x]=y; ans+=e[i].first; if(++tot==n-1) break; } } cout<<ans; } int main(){ cin>>n; for(int i=1; i<=n; i++) for(int j=1,k; j<=n; j++){ cin>>k; e[++m]={k,{i,j}}; } kruskal(); }
去掉的最大边权和 $=$ 总边权和 $-$ 最小生成树的边权和
// 最小生成树 Kruskal算法 O(MlogM) #include<bits/stdc++.h> #define int long long using namespace std; const int N=110,M=210; int n,m,tot,sum,ans,fa[N]; struct E{int x,y,w;}e[M]; //边集 int find(int u){ //并查集的找根 return fa[u]==u?u:fa[u]=find(fa[u]); } void kruskal(){ for(int i=1; i<=n; i++) fa[i]=i; sort(e+1,e+m+1,[&](E a,E b){return a.w<b.w;}); for(int i=1; i<=m; i++){ int x=find(e[i].x),y=find(e[i].y); if(x!=y){ fa[x]=y; ans+=e[i].w; if(++tot==n-1) break; } } cout<<sum-ans; } signed main(){ cin>>n>>m; for(int i=1,x,y,w;i<=m;i++){ cin>>x>>y>>w; sum+=w; e[i]={x,y,w}; } kruskal(); }
P1669 [USACO04DEC] Bad Cowtractors S - 洛谷
求最大生成树的边权和。
// 最大生成树 Kruskal算法 O(MlogM) #include<bits/stdc++.h> using namespace std; const int N=1010,M=20010; int n,m,tot,ans,fa[N]; pair<int,pair<int,int> >e[M]; //边集 int find(int u){ //并查集的找根 return fa[u]==u?u:fa[u]=find(fa[u]); } void kruskal(){ sort(e+1,e+m+1); //排序 reverse(e+1,e+m+1); //逆序 for(int i=0; i<=n; i++) fa[i]=i; for(int i=1; i<=m; i++){ int x=find(e[i].second.first),y=find(e[i].second.second); if(x!=y){ fa[x]=y; ans+=e[i].first; if(++tot==n-1) break; } } if(tot==n-1) printf("%d\n",ans); else puts("-1"); } int main(){ cin>>n>>m; for(int i=1,u,v,w;i<=m;i++){ cin>>u>>v>>w; e[i]={w,{u,v}}; } kruskal(); }
P2212 [USACO14MAR] Watering the Fields S - 洛谷
求最小生成树的边权和。
// 最小生成树 Kruskal算法 O(MlogM) #include<bits/stdc++.h> using namespace std; const int N=2010,M=4000010; int n,c,m,tot,ans,x[N],y[N],fa[N]; pair<int,pair<int,int> >e[M]; //边集 int find(int u){ //并查集的找根 return fa[u]==u?u:fa[u]=find(fa[u]); } void kruskal(){ sort(e+1,e+m+1); //排序 for(int i=1; i<=n; i++) fa[i]=i; for(int i=1; i<=m; i++){ int x=find(e[i].second.first),y=find(e[i].second.second); if(x!=y){ fa[x]=y; ans+=e[i].first; if(++tot==n) break; } } if(tot==n-1) printf("%d\n",ans); else puts("-1"); } int main(){ cin>>n>>c; for(int i=1;i<=n;i++){ scanf("%d %d",&x[i],&y[i]); for(int j=1;j<i;j++){ int d=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]); if(d>=c) e[++m]={d,{i,j}}; } } kruskal(); }
P2847 [USACO16DEC] Moocast G - 洛谷
求最小生成树的最大边权。
// 最小生成树 Kruskal算法 O(MlogM) #include<bits/stdc++.h> using namespace std; const int N=1010,M=1000010; int n,c,m,tot,ans,x[N],y[N],fa[N]; pair<int,pair<int,int> >e[M]; //边集 int find(int u){ //并查集的找根 return fa[u]==u?u:fa[u]=find(fa[u]); } void kruskal(){ sort(e+1,e+m+1); //排序 for(int i=1; i<=n; i++) fa[i]=i; for(int i=1; i<=m; i++){ int x=find(e[i].second.first),y=find(e[i].second.second); if(x!=y){ fa[x]=y; ans=e[i].first; if(++tot==n-1) break; } } printf("%d\n",ans); } int main(){ cin>>n; for(int i=1;i<=n;i++){ scanf("%d %d",&x[i],&y[i]); for(int j=1;j<i;j++){ int d=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]); e[++m]={d,{i,j}}; } } kruskal(); }
P2330 [SCOI2005] 繁忙的都市 - 洛谷 P1547 [USACO05MAR] Out of Hay S - 洛谷
求最小生成树的边数和最大边权。
// 最小生成树 Kruskal算法 O(MlogM) #include<bits/stdc++.h> using namespace std; const int N=2010,M=40010; int n,m,tot,ans,fa[N]; pair<int,pair<int,int> >e[M]; //边集 int find(int u){ //并查集的找根 return fa[u]==u?u:fa[u]=find(fa[u]); } void kruskal(){ sort(e+1,e+m+1); //排序 for(int i=1; i<=n; i++) fa[i]=i; for(int i=1; i<=m; i++){ int x=find(e[i].second.first),y=find(e[i].second.second); if(x!=y){ fa[x]=y; ans=e[i].first; if(++tot==n-1) break; } } cout<<n-1<<' '<<ans; } int main(){ cin>>n>>m; for(int i=1,u,v,c; i<=m; i++){ cin >>u>>v>>c; e[i]={c,{u,v}}; } kruskal(); }
浙公网安备 33010602011771号