为什么 Kruskal 可以AC,Prim 不可以?

P3366 【模板】最小生成树

Demon_master @ 2021-10-17 00:45:07

Prim(3TLE+1WA)

#include<bits/stdc++.h>
using namespace std;
const int maxn=2*1e5,maxm=5000*2+19;
int n,m;
struct P{
    int n,t,v;
}edge[maxn];

struct Q{
    int a;
    Q(){}
    Q(int b){a=b;}
};
bool operator<(const Q a,const Q b){
    return edge[a.a].v>edge[b.a].v;
}
int len=0;
int head[maxm];
bool vis[maxn];
int work(){
    priority_queue<Q> p;
    int ans=0;
    int cnt=0;
    p.push(Q(0));
    while(!p.empty()){
        int num=p.top().a;
        p.pop();
        if(vis[edge[num].t]) continue;
        vis[edge[num].t]=1;
        ans+=edge[num].v;
        cnt++;
        for(int i=head[edge[num].t];i;i=edge[i].n){
            if(vis[edge[i].t]) continue;
//          cout<<edge[num].t<<" "<<edge[i].t<<" "<<cnt<<" "<<ans<<endl;
            p.push(Q(i));
        }
    }
    if(cnt<n) return 0;
    return ans;
}

void build(int a,int b,int c){
    len++;
    edge[len].t=b;
    edge[len].v=c;
    edge[len].n=head[a];
    head[a]=len;
}

void read(){
    edge[0]={0,1,0};                             
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int f,t,v;
        scanf("%d%d%d",&f,&t,&v);
        build(f,t,v);
        build(t,f,v);
    }
    int ans=work();
    if(!ans) cout<<"ore";
    else cout<<ans;
}

int main(){
//  freopen("P3366_1.in","r",stdin);
    read();
}

Kruskal(AC)

#include<bits/stdc++.h>
using namespace std;
const int maxn=2*1e5;
int n,m;
struct P{
    int f,t,v;
}edge[maxn];
int fin[maxn],bian[maxn];
int C[maxn];

int Find(int a){
    return fin[a]==a ? a : fin[a]=Find(fin[a]);
}

void B(int a,int b){
    int A=Find(a),B=Find(b);
    if(C[A]<=C[B]) fin[A]=B;
    else fin[B]=A;
    if(C[A]==C[B]) C[B]++;
}

int Kruskal(){
    int ans=0,cnt=0;
    for(int i=1;i<=m;i++){
        int f=edge[bian[i]].f,t=edge[bian[i]].t;
        if(Find(f)==Find(t)) continue;
        cnt++;
        ans+=edge[bian[i]].v;
//      cout<<f<<" "<<t<<endl;
        B(t,f);
    }
//  cout<<ans<<" "<<cnt<<endl;
    if(cnt<n-1) ans=0;
    return ans;
}

bool cmp(int a,int b){
    return edge[a].v<edge[b].v;
}

void read(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) fin[i]=i,C[i]=1;
    for(int i=1;i<=m;i++) scanf("%d%d%d",&edge[i].f,&edge[i].t,&edge[i].v);
    for(int i=1;i<=m;i++) bian[i]=i;
    sort(bian+1,bian+1+m,cmp);
//  for(int i=1;i<=m;i++) cout<<edge[bian[i]].v<<" ";
//  cout<<endl;
    int ans=Kruskal();
    if(ans) cout<<ans<<endl;
    else cout<<"orz"<<endl;
}

int main (){
    freopen("P3366_1.in","r",stdin);
    read();
}

by Demon_master @ 2021-10-17 00:47:43

求大佬


by xfzf_shentao @ 2021-10-17 07:32:58

@Demon_master Kruskal在算法效率上是比Prim快的,因为Kruskal只需一次对权重的排序就能找到最小生成树”


by xfzf_shentao @ 2021-10-17 07:33:55

@Demon_master prim用二叉堆优化是复杂度,Kruskal是的复杂度。A是阿克曼函数的反函数,再加V因为并查集要初始化...要是prim用fib堆的话,应该是,因为fib堆update一次是的。。。好久不搞这个了,不知道是不是说错了。。。当然prim改一改还可以求次小生成树。。。


by BootsH @ 2021-10-17 07:47:24

堆的 cmp 函数不能借助外部变量


by int64 @ 2021-10-17 08:17:53

@xfzf_shentao

问一下,这句话啥意思:

prim用二叉堆优化是复杂度,Kruskal是的复杂度。

读了好多次没读懂,我语文白学了 /kk


by xfzf_shentao @ 2021-10-17 08:23:34

不知道诶,可能是复制的时候错了 (百度上查的)


by xfzf_shentao @ 2021-10-17 08:25:36

@int64 这里


by xfzf_shentao @ 2021-10-17 08:26:11

@int64 第一条


by int64 @ 2021-10-17 08:32:00

@xfzf_shentao 您这复杂度没复制上啊 /xyx


by xfzf_shentao @ 2021-10-17 08:39:12

@int64 好像复制不上


|