P3366 【模板】KrusKal与Prim解题模板

题目描述

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

输入格式

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

接下来 M M M 行每行包含三个整数 X i , Y i , Z i X_i,Y_i,Z_i Xi,Yi,Zi,表示有一条长度为 Z i Z_i Zi 的无向边连接结点 X i , Y i X_i,Y_i Xi,Yi

输出格式

如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出 orz

样例 #1

样例输入 #1

4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3

样例输出 #1

7

提示

数据规模:

对于 20 % 20\% 20% 的数据, N ≤ 5 N\le 5 N5 M ≤ 20 M\le 20 M20

对于 40 % 40\% 40% 的数据, N ≤ 50 N\le 50 N50 M ≤ 2500 M\le 2500 M2500

对于 70 % 70\% 70% 的数据, N ≤ 500 N\le 500 N500 M ≤ 1 0 4 M\le 10^4 M104

对于 100 % 100\% 100% 的数据: 1 ≤ N ≤ 5000 1\le N\le 5000 1N5000 1 ≤ M ≤ 2 × 1 0 5 1\le M\le 2\times 10^5 1M2×105 1 ≤ Z i ≤ 1 0 4 1\le Z_i \le 10^4 1Zi104

样例解释:

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

Kruskal

点个免费的赞吧谢谢ヽ( ̄ω ̄( ̄ω ̄〃)#include <bits/stdc++.h>
using namespace std;
const int N = 5005,M = 2e5+1;
struct Edge{int u,v,w;}edge[M];       //用最简单且最省空间的结构体数组存边
bool cmp(Edge a, Edge b){ return a.w < b.w;}       //从小到大排序
int s[N];                             //并查集
int find_set(int x){                  //查询并查集,返回x的根
    if(x != s[x])s[x] = find_set(s[x]);//路径压缩
    return s[x];
}
int n,m;                              // n个点,m条边
void kruskal(){
    sort(edge+1, edge+m+1, cmp);      //对边做排序
    for(int i=1; i<=n; i++) s[i]=i;   //并查集初始化
    int ans = 0, cnt=0;               //cnt: 计数已加入MST的边数
    for(int i=1; i<=m; i++){          //贪心:逐一加入每条边
        if(cnt == n-1)break;      	  //小优化:不要也行
        int xset = find_set(edge[i].u); //边的前端点u属于哪个集?
        int yset = find_set(edge[i].v); //边的后端点v属于哪个集?
        if(xset == yset) continue;     //属于同一个集:产生了环,丢弃
        else{                         //不属于同一个集
		   ans += edge[i].w;         //增加MST长度
		   s[xset]= yset;            //合并并查集
		   cnt++;                    //更新MST中的边数
		}
	}
	if(cnt == n-1) cout << ans;       //n-1条边
	else cout << "orz";               //图不是连通的
}
int main(){
cin >> n >> m;
for(int i=1; i<=m; i++)  cin >> edge[i].u >> edge[i].v >> edge[i].w;
kruskal();
return 0;
}

Prim:

点个免费的赞吧谢谢ヽ( ̄ω ̄( ̄ω ̄〃)#include <bits/stdc++.h>
using namespace std;
const int N=5005,M = 2e5+1;
struct edge{                              //记录边
int to, w;  
edge(int a,int b){ to = a, w = b;}    //赋值
};
vector <edge>G[M];
struct node {
    int id, dis;   //id:点;dis:边
    node(int a, int b){ id = a, dis = b;}  //赋值
    bool operator < (const node &u) const { return dis > u.dis; }
};
int n, m;
bool done[N];                //done[i]=ture: 表示点i已经在MST中
void  prim() {               //对比dijkstra: 求s到其他所有点的最短路
    int s = 1;               //从任意点开始,例如从1开始
    for(int i =1;i<=N;i++)   done[i]=false;   //初始化
    priority_queue<node> q;
    q.push(node(s, 0));      //从s点开始处理队列
    int ans=0,cnt=0;
    while (!q.empty()) {
        node u = q.top();   q.pop();    //pop出距集合U最近的点u
        if (done[u.id])     continue;   //丢弃已经在MST中的点,有判圈的作用
        done[u.id] = true;              //标记
        ans += u.dis;
        cnt++;                          //统计点数
        for (int i = 0; i< G[u.id].size(); i++) {    //检查点u的所有邻居
            edge y = G[u.id][i];        //一个邻居y
            if (done[y.to])   continue; //丢弃已经在MST中的点
            q.push(node(y.to, y.w));    //扩展新的邻居,放进优先队列
        }
    }
    if(cnt == n) cout << ans;           //cnt=n个点。注意在kruskal代码中cnt是边数
else cout << "orz";
}
int main() {
    cin>>n>>m;
    for(int i=1; i<=m; i++) {
        int a,b,w;   cin>>a>>b>>w;
        G[a].push_back(edge(b,w));  G[b].push_back(edge(a,w));  //双向边
    }
    prim();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值