练习38,最小生成树MST【Prim算法+堆优化】

P3366 【模板】最小生成树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

普通版

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define NOTLE ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define T int TT;cin >> TT;while (TT--)
#define lint long long
#define pb push_back
#define eb emplace_back
int last[400010],ne[400010],to[400010],w[400010],cnt=0;
int d[5010],n,m,ans;
int vis[5010];
void add(int x,int y,int z){//链式前向星存边
	to[++cnt]=y;
	ne[cnt]=last[x];
	last[x]=cnt;
	w[cnt]=z;
}
int prim(){
	memset(d,INF,sizeof(d));//没有搜索到的点设置为最大值

	for(int i=last[1];i;i=ne[i]){
		d[to[i]]=min(d[to[i]],w[i]);
	}
	int now=1,tot=0;
    while(++tot<n){//最小生成树边数等于点数n-1
        int minn=INF;
        vis[now]=1;//标记走过的点
        for(int i=1;i<=n;++i) //找最短边连的点
            if(!vis[i] && minn>d[i]){
                minn=d[i];
				now=i;
            }
        if(minn==INF) return -1; //如果没找到,说明最小生成树不存在
        ans+=minn;
        for(int i=last[now];i;i=ne[i]) //枚举now的所有连边,更新d数组
        	if(d[to[i]]>w[i] && !vis[to[i]]){
        		d[to[i]]=w[i];
        	}
    }
    return ans;
}
int main(){
    cin >> n >> m;
    for(int i=1;i<=m;++i){
        int x,y,z;
        cin >> x >> y >> z;
        add(x,y,z),add(y,x,z);
    }
    int pr=prim();
    if(pr!=-1) cout << pr;
    else cout << "orz";
    return 0;
}

堆优化版

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define NOTLE ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define T int TT;cin >> TT;while (TT--)
#define lint long long
#define pb push_back
#define eb emplace_back
int last[400010],ne[400010],to[400010],w[400010],cnt=0,tot=0;
int d[5010],n,m,ans;
int vis[5010];
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> p; //小根堆

void add(int x,int y,int z){
	to[++cnt]=y;
	ne[cnt]=last[x];
	last[x]=cnt;
	w[cnt]=z;
}
int prim(){
	memset(d,INF,sizeof(d));//没有搜索到的点设置为最大值
	p.push(make_pair(0,1));
    while(!p.empty()){
        int now=p.top().second,nowa=p.top().first;
        p.pop();
        if(vis[now]) continue;
        vis[now]=1;
        ans+=nowa;
        for(int i=last[now];i;i=ne[i])
        	if(d[to[i]]>w[i] && !vis[to[i]]){
        		d[to[i]]=w[i];
        		p.push(make_pair(d[to[i]],to[i]));
        	}
        tot++;
    }
    return ans;
}
int main(){
    cin >> n >> m;
    for(int i=1;i<=m;++i){
        int x,y,z;
        cin >> x >> y >> z;
        add(x,y,z),add(y,x,z);
    }
    int pr=prim();
    if(tot==n) cout << pr;
    else cout << "orz";
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ILECY

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值