洛谷 P3366 【模板】最小生成树

题目描述

如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz

输入输出格式

输入格式:

第一行包含两个整数 NM ,表示该图共有 N 个结点和 M 条无向边。( N5000,M200000

接下来 M 行每行包含三个整数 XiYiZi,表示有一条长度为 Zi 的无向边连接结点 XiYi

输出格式:

输出包含一个数,即最小生成树的各边的长度之和;如果该图不连通则输出 orz

输入输出样例

输入样例#1:
4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3
输出样例#1:
7

说明

时空限制:

1000ms,128M

数据规模:

对于 20% 的数据: N5,M20

对于 40% 的数据: N50,M2500

对于 70% 的数据: N500,M10000

对于 100% 的数据: N5000,M200000

样例解释:

qwq

所以最小生成树的总边权为 2+2+3=7


solution

  • 对于 n1000 的数据,Prim模板题

  • 其余的数据,Kruskal模板题

code

其实还想写堆优化的prim来着,但是没找到代码风格和我差不多的模板…sad
就先用这两个吧
还有一遍速度对比的文章,感兴趣的话可以戳这里

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;

template<typename T>
void input(T &x) {
    x=0; T a=1;
    register char c=getchar();
    for(;c<'0'||c>'9';c=getchar())
        if(c=='-') a=-1;
    for(;c>='0'&&c<='9';c=getchar())
        x=x*10+c-'0';
    x*=a;
    return;
}

namespace __Prim {

    const int MAXN=1000;
    const int inf=2147483647;

    int G[MAXN][MAXN];
    int lowcost[MAXN];
    bool vis[MAXN];

    void Prim(int n,int m) {
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                G[i][j]=inf*(i!=j);
        for(int i=1;i<=m;i++) {
            int u,v,w;
            input(u),input(v),input(w);
            if(w<G[u][v]) G[u][v]=w;
            if(w<G[v][u]) G[v][u]=w;
        }
        for(int i=1;i<=n;i++)
            lowcost[i]=G[1][i],vis[i]=false;
        vis[1]=true;
        int MST=0;
        for(int k=1;k<n;k++) {
            int Min=inf,u=-1;
            for(int i=1;i<=n;i++)
                if(!vis[i]&&lowcost[i]<Min)
                    Min=lowcost[u=i];
            if(u==-1) {
                printf("orz");
                return;
            }
            vis[u]=true;
            MST+=Min;
            for(int v=1;v<=n;v++)
                if(!vis[v]&&lowcost[v]>G[u][v])
                    lowcost[v]=G[u][v];
        }
        printf("%d",MST);
        return;
    }

}

namespace __Kruskal {

    const int MAXN=5010;
    const int MAXM=200010;

    struct Edge {
        int u,v,w;
        Edge(int u=0,int v=0,int w=0):
            u(u),v(v),w(w) {}
        bool operator < (const Edge &q) const {
            return w<q.w;
        }
    };

    Edge edge[MAXM];
    int father[MAXN];

    int Find(int x) {
        return father[x]==x?x:father[x]=Find(father[x]);
    }

    bool Union(int x,int y) {
        if((x=Find(x))==(y=Find(y)))
            return false;
        father[x]=y;
        return true;
    }

    void Kruskal(int n,int m) {
        for(int i=1;i<=m;i++)
            input(edge[i].u),
            input(edge[i].v),
            input(edge[i].w);
        for(int i=1;i<=n;i++)
            father[i]=i;
        sort(edge+1,edge+m+1);
        int MST=0,k=0;
        for(int i=1;i<=m;i++)
            if(Union(edge[i].u,edge[i].v))
                MST+=edge[i].w,k++;
        if(k==n-1) printf("%d",MST);
        else printf("orz");
        return;
    }

}

int main() {
    int n,m;
    input(n),input(m);
    if(n<=1000) __Prim::Prim(n,m);
    else __Kruskal::Kruskal(n,m);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值