- admin's blog
最小生成树
- @ 2024-3-16 9:59:49
最小生成树
最小生成树就是:在一张图中,我们将
Prim
从一个节点开始,依次贪心地取它的边权最小的几个边,如果取的边连接的点没有被加到树中,加入这个点,答案加上这个边权,知道所有的点都被加入到树上为止。
Code
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+12,M=4e5+12;
int n,m,u,v,w,cnt,tot,use[N],head[N],ans;
struct Edge{
int nex,to,w;
bool operator < ( const Edge &other ) const
{
return other.w<w;
}
}edge[M];
void addedge(int u,int v,int w)
{
cnt++;
edge[cnt]={ head[u],v,w };
head[u]=cnt;
}
priority_queue<Edge>q;
void prim(){
for(int i=head[1];i;i=edge[i].nex)
{
q.push(edge[i]);
use[1]=1;
tot=1;
}
while( !q.empty() )
{
Edge l=q.top();
q.pop();
int y=l.to,w=l.w;
if( use[y] ) continue;
ans+=w;
tot++;
use[y]=1;
for(int i=head[y];i;i=edge[i].nex)
{
q.push(edge[i]);
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>u>>v>>w;
addedge(u,v,w);
addedge(v,u,w);
}
prim();
if( tot==n ) cout<<ans;
else cout<<"orz";
}
Kruskal
Prim是贪心加点,这个就是贪心加边。
首先,我们对所有的边进行排序,然后贪心地取边,如果这个边的两个节点 u、v不是在一棵树上(并查集),那么这个边就可以取,反之则不能
Code
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+12,M=4e5+12;
int fa[N],n,m,cnt,tot,ans,u,v,w;
int use[N];
struct Edge{
int from,to,w;
bool operator < ( Edge & other )
{
return w<other.w;
}
}edge[M];
int find(int x)
{
if( x==fa[x] ) return x;
return fa[x]=find(fa[x]);
}
void addedge(int u,int v,int w)
{
cnt++;
edge[cnt]={u,v,w};
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=m;i++)
{
cin>>u>>v>>w;
addedge(u,v,w);
addedge(v,u,w);
}
sort(edge+1,edge+1+2*m);
for(int i=1;i<=1+2*m;i++)
{
u=edge[i].from,v=edge[i].to,w=edge[i].w;
int a=find(u),b=find(v);
if( a!=b )
{
tot++;
ans+=w;
fa[a]=b;
}
}
if( tot==n-1 ) cout<<ans;
else cout<<"orz";
}