最小生成树

Kruskal

#include<bits/stdc++.h>
#define il inline
#define ri register int
using namespace std;
il int read()
{
    int as=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') as=(as<<3)+(as<<1)+(ch^48),ch=getchar();
    return as*f;
}
const int maxm=2e5+5,inf=0x3f3f3f3f;
int n,m,cnt,ans,tot,now=1,fa[5005];
bool vis[5005];
struct qwq{int u,v,w;}edge[maxm<<1];
il bool cmp(qwq x,qwq y){return x.w<y.w;}
il int Find(int x)
{
    while(fa[x]!=fa[fa[x]]) fa[x]=fa[fa[x]];
    return fa[x];
}
il void Merge(int x,int y)
{
    if(Find(x)!=Find(y)) fa[Find(x)]=Find(y);
}
il int Kruskal()
{
    sort(edge+1,edge+m+1,cmp);
    for(ri i=1;i<=m;++i)
    {
        int Fu=Find(edge[i].u),Fv=Find(edge[i].v);
        if(Fu==Fv) continue;
        ans+=edge[i].w,Merge(Fu,Fv);
        if(++cnt==n-1) break;
    }
    for(ri i=2;i<=n;++i) 
        if(Find(1)!=Find(i)) return -1;
    return ans;
}
int main()
{
    n=read(),m=read();
    for(ri i=1;i<=n;++i) fa[i]=i;
    for(ri i=1;i<=m;++i) 
        edge[i].u=read(),edge[i].v=read(),edge[i].w=read();
    int K=Kruskal();
    if(K==-1) return printf("orz"),0;
    else printf("%d",K);
    return 0;
}

Prim

#include<bits/stdc++.h>
#define il inline
#define ri register int
using namespace std;
il int read()
{
    int as=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') as=(as<<3)+(as<<1)+(ch^48),ch=getchar();
    return as*f;
}
const int maxm=2e5+5,inf=0x3f3f3f3f;
//dis:已经加入最小生成树的的点到没有加入的点的最短距离
int n,m,head[5005],dis[5005],cnt,tot,now=1,ans;
bool vis[5005];
struct qwq{int to,w,nxt;}edge[maxm<<1];
il void add(int u,int v,int w)
{
    edge[++cnt].to=v,edge[cnt].w=w,
    edge[cnt].nxt=head[u],head[u]=cnt;
}
il int Prim()//朴素版本 n^2
{
    for(ri i=2;i<=n;++i) dis[i]=inf;
    for(ri i=head[1];i;i=edge[i].nxt) //重边 
        dis[edge[i].to]=min(dis[edge[i].to],edge[i].w);
    while(++tot<n)
    {
        int minn=inf;
        vis[now]=1;
        for(ri i=1;i<=n;++i)//枚举没有走过的点找最小值当新边 
            if(!vis[i]&&minn>dis[i])
                minn=dis[i],now=i;
        if(minn==inf) return -1;
        ans+=minn;
        for(ri i=head[now];i;i=edge[i].nxt)//枚举now的所有连边 
        {
            int t=edge[i].to;
            if(dis[t]>edge[i].w&&!vis[t])
                dis[t]=edge[i].w;
        }
    }
    return ans;
}
int main()
{
    n=read(),m=read();
    for(ri i=1,u,v,w;i<=m;++i) 
        u=read(),v=read(),w=read(),add(u,v,w),add(v,u,w);
    if(Prim()==-1) printf("orz");
    else printf("%d",Prim());
    return 0;
}
posted @ 2022-09-23 15:11  Bertidurlah  阅读(35)  评论(1)    收藏  举报