P3366 模板最小生成树 (贪心+并查集,kruskal)
Posted load-star
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3366 模板最小生成树 (贪心+并查集,kruskal)相关的知识,希望对你有一定的参考价值。
题目描述
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz
。
输入格式
第一行包含两个整数 N,MN,M,表示该图共有 NN 个结点和 MM 条无向边。
接下来 MM 行每行包含三个整数 X_i,Y_i,Z_iXi?,Yi?,Zi?,表示有一条长度为 Z_iZi? 的无向边连接结点 X_i,Y_iXi?,Yi?。
输出格式
如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出 orz
。
输入输出样例
输入 #1
4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3
输出 #1
7
说明/提示
数据规模:
对于 20\%20% 的数据,Nle 5N≤5,Mle 20M≤20。
对于 40\%40% 的数据,Nle 50N≤50,Mle 2500M≤2500。
对于 70\%70% 的数据,Nle 500N≤500,Mle 10^4M≤104。
对于 100\%100% 的数据:1le Nle 50001≤N≤5000,1le Mle 2 imes 10^51≤M≤2×105。
样例解释:
所以最小生成树的总边权为 2+2+3=72+2+3=7.
题解:
该题可以利用贪心的思想,将所有边按照权值从小到大进行排列,从最小的开始取,一定就是最短路,同时利用并查集来判断两个点是否已经连通。具体见代码。
#define _CRT_SECURE_NO_DepRECATE #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <iostream> #include <cmath> #include <iomanip> #include <string> #include <algorithm> #include <bitset> #include <cstdlib> #include <cctype> #include <iterator> #include <vector> #include <cstring> #include <cassert> #include <map> #include <queue> #include <set> #include <stack> #include <stdio.h> #define ll long long #define INF 0x3f3f3f3f #define LINF 0x3f3f3f3f3f3f3f3f #define ld long double #define rep(i, a, b) for(int i = a; i < (b); ++i) const ld pi = acos(-1.0L), eps = 1e-8; ll qx[4] = { 0,0,1,-1 }, qy[4] = { 1,-1,0,0 }, qxx[2] = { 1,-1 }, qyy[2] = { 1,-1 }; using namespace std; int n, m, a, b, c, d, e, ans = 0, cnt = 0; struct node { int parent, shu; }shu[10010]; struct nodee { int x, y, z;//x,y为点 z为权值 }tu[200010]; bool cmp(nodee x, nodee y)//排序权值 { return x.z < y.z; } int find(int x) { while (shu[x].parent != x) { x = shu[x].parent = shu[shu[x].parent].parent; } return x; } inline void kruskal() { sort(tu, tu + m, cmp); rep(i, 0, m) { d = find(tu[i].x); e = find(tu[i].y); if (d == e)//当两点已连通则换下一条边 { continue; } ans += tu[i].z; shu[d].parent = e;//合并 if (++cnt == n - 1)//已经全部合并的时候就结束循环 { break; } } } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n >> m; for (int i = 1; i <= n; i++) { shu[i].parent = i; } rep(i, 0, m) { cin >> tu[i].x >> tu[i].y >> tu[i].z; } kruskal(); if (ans == 0) { cout << "orz" << endl; return 0; } cout << ans << endl; return 0; }
以上是关于P3366 模板最小生成树 (贪心+并查集,kruskal)的主要内容,如果未能解决你的问题,请参考以下文章
最小生成树模板题POJ - 1287-prim+kruskal
代码源 Div1 - 109#454. Minimum Or Spanning Tree(最小生成树,边权按位或,贪心,并查集) CF1624G