一、核心思想
将输入的数据由小到大进行排序,再使用并查集算法(传送门)将每个点连接起来,同时求和。
个人认为这个算法比较偏向暴力,有些题可能会超时。
二、例题 洛谷—P3366
题目地址:https://www.luogu.org/problemnew/show/P3366
这是一道非常好的克鲁斯卡尔算法的模板题。
题目描述
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz
输入输出格式
输入格式:
第一行包含两个整数N、M,表示该图共有N个结点和M条无向边。(N<=5000,M<=200000)
接下来M行每行包含三个整数Xi、Yi、Zi,表示有一条长度为Zi的无向边连接结点Xi、Yi
输出格式:
输出包含一个数,即最小生成树的各边的长度之和;如果该图不连通则输出orz
输入输出样例
输入样例:
4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3
输出样例:
7
AC代码:
这段是符合题意的改良代码,一开始我提交的时候没有做orz的输出,由于题的数据问题导致没有设计orz也过了😄😄😄。
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int root[500000];
int book[500000];
int n, m;
int ans;
struct node
{
int be, en, dis;
}road[500000];
bool cmp( node a, node b)
{
return a.dis < b.dis;
}
int findx( int a)
{
if (a == root[a])
return a;
else
return root[a] = findx(root[a]);
}
void mix( int a, int b)
{
int fr = findx(a), lr = findx(b);
if(fr != lr)
root[b] = fr;
}
int kruscal()
{
int sum = 0;
int t1, t2;
for( int i = 1; i <= m; i++)
{
t1 = findx(road[i].be);
t2 = findx(road[i].en);
if( t1 != t2)
{
sum += road[i].dis;
ans++;
mix(t1,t2);
}
if(ans == n-1)
break;
}
return sum;
}
int main()
{
int sum;
cin >> n >> m;
for( int i = 1; i <= n; i++)
root[i] = i;
for( int i = 1; i <= m; i++)
scanf("%d%d%d", &road[i].be, &road[i].en, &road[i].dis);
sort( road+1, road+m+1, cmp); //对输入的数据进行排序
sum = kruscal();
if(ans == n-1)
cout << sum << endl;
else
cout << "orz" << endl;
return 0;
}
能力有限,有错误麻烦指出,万分感谢。