Kruskal 如何优化内存

P3366 【模板】最小生成树

Violet_Evergardon @ 2024-08-12 11:47:11

8#9#10MLE #13TLE

我是直接存边,用两条有向边表示一条无向边

#include<iostream>
#include<stdio.h>
#include<queue>
using namespace std;
const int N=5005;
const int M=2e5+5;
int n,m,cnt,ans;
int fa[N];
struct B{
    int u,v,w;
}edge[M];
struct cmp{
    bool operator()(B a,B b){return a.w>b.w;}
};
priority_queue<B,vector<B>,cmp> q;
int find(int a){
    if(fa[a]!=a)    return fa[a]=find(fa[a]);
    return fa[a];
}
void jianbian(int a,int b,int c){
    edge[++cnt].u=a,edge[cnt].v=b,edge[cnt].w=c;
    q.push(edge[cnt]);
}
void mix(int a,int b)
{
    if(fa[a]==fa[b])    return ;
    fa[a]=find(a),fa[b]=find(b);
    fa[fa[b]]=fa[a];
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        fa[i]=i;
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        jianbian(a,b,c);jianbian(b,a,c);
    }

    //Kruskal
    for(int i=1;i<=n-1;i++)
    {
        B t=q.top();
        while(find(t.u)==find(t.v)) q.pop(),t=q.top();
        ans+=t.w;
        mix(t.v,t.u);
    }

    for(int i=2;i<=n;i++)
        if(find(1)!=find(i))
        {
            cout<<"orz"<<endl;
            return 0;
        }
    cout<<ans<<endl;
    return 0;   
}

by Fur_Zes @ 2024-08-12 11:51:38

@Violet_Evergardon 为什么要用有向边啊/yiw


by Fur_Zes @ 2024-08-12 11:52:49

@Violet_Evergardon 用并查集直接去看当前节点是否在生成树里就好了啊,你这建了双倍的边浪费空间的


by _8008008 @ 2024-08-12 11:55:45

@As2O3 应该不是这里的问题,用两个有向边表示无向边是常规操作


by Fur_Zes @ 2024-08-12 11:57:36

@_8008008 但是他浪费空间啊,lz有报错MLE的


by _8008008 @ 2024-08-12 11:59:05

那试试吧


by Violet_Evergardon @ 2024-08-12 16:37:55

@As2O3 是这个问题,在这里确实没有必要建两边。改过后就没有MLE了。但#13还是T了,是因为用堆了吗?虽然一个sort可以搞定,但都是nlogn的复杂度啊。


by Fur_Zes @ 2024-08-12 16:41:37

@Violet_Evergardon 可能是,但我没学堆排,我尽量帮忙找找问题


by Fur_Zes @ 2024-08-12 17:01:18

@Violet_Evergardon

while(find(t.u)==find(t.v)) q.pop(),t=q.top();

这句话太慢了,个人感觉这个for套while可以卡到 O(n^2),找找其他判不连通的方法吧,最好还是用回sort


|